@player-tools/xlr-utils 0.0.2-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/index.cjs.js +526 -0
- package/dist/index.d.ts +126 -0
- package/dist/index.esm.js +477 -0
- package/package.json +35 -0
- package/src/annotations.ts +230 -0
- package/src/index.ts +5 -0
- package/src/test-helpers.ts +72 -0
- package/src/ts-helpers.ts +356 -0
- package/src/type-checks.ts +106 -0
- package/src/validation-helpers.ts +88 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import type {
|
|
3
|
+
NamedType,
|
|
4
|
+
NamedTypeWithGenerics,
|
|
5
|
+
NodeType,
|
|
6
|
+
NodeTypeWithGenerics,
|
|
7
|
+
PrimitiveTypes,
|
|
8
|
+
} from '@player-tools/xlr';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Returns if the Object Property is optional
|
|
12
|
+
*/
|
|
13
|
+
export function isOptionalProperty(node: ts.PropertySignature): boolean {
|
|
14
|
+
return node.questionToken?.kind === ts.SyntaxKind.QuestionToken;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Returns if the node is an Interface or Type with Generics
|
|
19
|
+
*/
|
|
20
|
+
export function isGenericInterfaceDeclaration(
|
|
21
|
+
node: ts.InterfaceDeclaration
|
|
22
|
+
): boolean {
|
|
23
|
+
const length = node.typeParameters?.length;
|
|
24
|
+
return length ? length > 0 : false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Returns if the node is an Type Declaration with Generics
|
|
29
|
+
*/
|
|
30
|
+
export function isGenericTypeDeclaration(
|
|
31
|
+
node: ts.TypeAliasDeclaration
|
|
32
|
+
): boolean {
|
|
33
|
+
const length = node.typeParameters?.length;
|
|
34
|
+
return length ? length > 0 : false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Returns if the referenced type is a generic
|
|
39
|
+
*/
|
|
40
|
+
export function isTypeReferenceGeneric(
|
|
41
|
+
node: ts.TypeReferenceNode,
|
|
42
|
+
typeChecker: ts.TypeChecker
|
|
43
|
+
): boolean {
|
|
44
|
+
const symbol = typeChecker.getSymbolAtLocation(node.typeName);
|
|
45
|
+
if (symbol && symbol.declarations) {
|
|
46
|
+
return symbol.declarations[0].kind === ts.SyntaxKind.TypeParameter;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type TopLevelDeclaration =
|
|
53
|
+
| ts.InterfaceDeclaration
|
|
54
|
+
| ts.TypeAliasDeclaration;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Returns if the node is an interface or a type declaration
|
|
58
|
+
*/
|
|
59
|
+
export function isTopLevelNode(node: ts.Node): node is TopLevelDeclaration {
|
|
60
|
+
return (
|
|
61
|
+
node.kind === ts.SyntaxKind.InterfaceDeclaration ||
|
|
62
|
+
node.kind === ts.SyntaxKind.TypeAliasDeclaration
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Returns if the NodeType has generic tokens
|
|
68
|
+
*/
|
|
69
|
+
export function isGenericNodeType<T extends NodeType = NodeType>(
|
|
70
|
+
nt: NodeType
|
|
71
|
+
): nt is NodeTypeWithGenerics<T> {
|
|
72
|
+
return (nt as NodeTypeWithGenerics).genericTokens?.length > 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Returns if the named type has generic tokens
|
|
77
|
+
*/
|
|
78
|
+
export function isGenericNamedType<T extends NamedType = NamedType>(
|
|
79
|
+
nt: NodeType
|
|
80
|
+
): nt is NamedTypeWithGenerics<T> {
|
|
81
|
+
return (nt as NamedTypeWithGenerics).genericTokens?.length > 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Returns if the node is a `PrimitiveTypes`
|
|
86
|
+
*/
|
|
87
|
+
export function isPrimitiveTypeNode(node: NodeType): node is PrimitiveTypes {
|
|
88
|
+
return (
|
|
89
|
+
node.type === 'string' ||
|
|
90
|
+
node.type === 'number' ||
|
|
91
|
+
node.type === 'boolean' ||
|
|
92
|
+
node.type === 'null' ||
|
|
93
|
+
node.type === 'template' ||
|
|
94
|
+
node.type === 'any' ||
|
|
95
|
+
node.type === 'never' ||
|
|
96
|
+
node.type === 'undefined' ||
|
|
97
|
+
node.type === 'unknown'
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Type Guard for non-null values
|
|
103
|
+
*/
|
|
104
|
+
export function isNonNullable<T>(a: T | null | undefined): a is NonNullable<T> {
|
|
105
|
+
return a !== null || a !== undefined;
|
|
106
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Node } from 'jsonc-parser';
|
|
2
|
+
import type { ConditionalType, NodeType } from '@player-tools/xlr';
|
|
3
|
+
import { isPrimitiveTypeNode } from './type-checks';
|
|
4
|
+
|
|
5
|
+
export interface PropertyNode {
|
|
6
|
+
/** Equivalent Property Name */
|
|
7
|
+
key: string;
|
|
8
|
+
|
|
9
|
+
/** Equivalent Property Value */
|
|
10
|
+
value: Node;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Takes a property node and returns the underlying Key/Value Pairs
|
|
15
|
+
*/
|
|
16
|
+
export function propertyToTuple(node: Node): PropertyNode {
|
|
17
|
+
let key = node.children?.[0].value as string;
|
|
18
|
+
if (key.includes('-')) {
|
|
19
|
+
key = `'${key}'`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
key,
|
|
24
|
+
value: node.children?.[1] as Node,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Turns a node's children into a map for easy access
|
|
30
|
+
*/
|
|
31
|
+
export function makePropertyMap(node: Node): Map<string, Node> {
|
|
32
|
+
const m = new Map();
|
|
33
|
+
node.children?.forEach((child) => {
|
|
34
|
+
const property = propertyToTuple(child);
|
|
35
|
+
m.set(property.key, property.value);
|
|
36
|
+
});
|
|
37
|
+
return m;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Checks if property is a leaf node or another node
|
|
42
|
+
*/
|
|
43
|
+
export function isNode(obj: Node | string | number | boolean): obj is Node {
|
|
44
|
+
return (
|
|
45
|
+
typeof obj !== 'string' ||
|
|
46
|
+
typeof obj !== 'number' ||
|
|
47
|
+
typeof obj !== 'boolean'
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Attempts to resolve a conditional type
|
|
53
|
+
*/
|
|
54
|
+
export function resolveConditional(conditional: ConditionalType): NodeType {
|
|
55
|
+
const { left, right } = conditional.check;
|
|
56
|
+
if (isPrimitiveTypeNode(left) && isPrimitiveTypeNode(right)) {
|
|
57
|
+
if (left.const && right.const) {
|
|
58
|
+
return left.const === right.const
|
|
59
|
+
? conditional.value.true
|
|
60
|
+
: conditional.value.false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// special case for any/unknown being functionally the same
|
|
64
|
+
if (
|
|
65
|
+
(left.type === 'any' || left.type === 'unknown') &&
|
|
66
|
+
(right.type === 'any' || right.type === 'unknown')
|
|
67
|
+
) {
|
|
68
|
+
return conditional.value.true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// special case for null/undefined being functionally the same
|
|
72
|
+
if (
|
|
73
|
+
(left.type === 'null' || left.type === 'undefined') &&
|
|
74
|
+
(right.type === 'null' || right.type === 'undefined')
|
|
75
|
+
) {
|
|
76
|
+
return conditional.value.true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (left.type === right.type) {
|
|
80
|
+
return conditional.value.true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return conditional.value.false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// unable to process return original
|
|
87
|
+
return conditional;
|
|
88
|
+
}
|