-
Notifications
You must be signed in to change notification settings - Fork 187
/
define.ts
175 lines (138 loc) · 4.31 KB
/
define.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
import type {
Arguments,
HelperCapabilities,
HelperManager,
ModifierManager,
Owner,
} from '@glimmer/interfaces';
import { registerDestructor } from '@glimmer/destroyable';
import {
helperCapabilities,
modifierCapabilities,
setComponentTemplate,
setHelperManager,
setModifierManager,
} from '@glimmer/manager';
import { setOwner } from '@glimmer/owner';
import { templateOnlyComponent } from '@glimmer/runtime';
import { createTemplate } from '../compile';
interface SimpleHelperState {
fn: (...args: unknown[]) => unknown;
args: Arguments;
}
class FunctionalHelperManager implements HelperManager<SimpleHelperState> {
capabilities = helperCapabilities('3.23', {
hasValue: true,
});
createHelper(fn: () => unknown, args: Arguments) {
return { fn, args };
}
getValue({ fn, args }: SimpleHelperState) {
return fn(...args.positional);
}
getDebugName(fn: Function) {
return fn.name || '(anonymous function)';
}
}
const FUNCTIONAL_HELPER_MANAGER = new FunctionalHelperManager();
const FUNCTIONAL_HELPER_MANAGER_FACTORY = () => FUNCTIONAL_HELPER_MANAGER;
type SimpleModifierFn = (...args: unknown[]) => (() => void) | undefined;
interface SimpleModifierState {
fn: SimpleModifierFn;
args: Arguments;
element: Element | undefined;
destructor: (() => void) | undefined;
}
class FunctionalModifierManager implements ModifierManager<SimpleModifierState> {
capabilities = modifierCapabilities('3.22');
createModifier(fn: SimpleModifierFn, args: Arguments) {
return { fn, args, element: undefined, destructor: undefined };
}
installModifier(state: SimpleModifierState, element: Element) {
state.element = element;
this.setupModifier(state);
}
updateModifier(state: SimpleModifierState) {
this.destroyModifier(state);
this.setupModifier(state);
}
setupModifier(state: SimpleModifierState) {
let { fn, args, element } = state;
state.destructor = fn(element, args.positional, args.named);
}
destroyModifier(state: SimpleModifierState) {
if (typeof state.destructor === 'function') {
state.destructor();
}
}
getDebugName(fn: Function) {
return fn.name || '(anonymous function)';
}
}
const FUNCTIONAL_MODIFIER_MANAGER = new FunctionalModifierManager();
const FUNCTIONAL_MODIFIER_MANAGER_FACTORY = () => FUNCTIONAL_MODIFIER_MANAGER;
export interface DefineComponentOptions {
// defaults to templateOnlyComponent
definition?: object;
// defaults to true when some scopeValues are passed and false otherwise
strictMode?: boolean;
// additional strict-mode keywords
keywords?: string[];
}
export function defineComponent(
scopeValues: Record<string, unknown> | null,
templateSource: string,
options: DefineComponentOptions = {}
) {
let strictMode: boolean;
if (typeof options.strictMode === 'boolean') {
strictMode = options.strictMode;
} else {
strictMode = scopeValues !== null;
}
let keywords = options.keywords ?? [];
let definition = options.definition ?? templateOnlyComponent();
let templateFactory = createTemplate(templateSource, { strictMode, keywords }, scopeValues ?? {});
setComponentTemplate(templateFactory, definition);
return definition;
}
export function defineSimpleHelper<T extends Function>(helperFn: T): T {
return setHelperManager(FUNCTIONAL_HELPER_MANAGER_FACTORY, helperFn);
}
export function defineSimpleModifier<T extends Function>(modifierFn: T): T {
return setModifierManager(FUNCTIONAL_MODIFIER_MANAGER_FACTORY, modifierFn);
}
export class TestHelperManager {
capabilities: HelperCapabilities = helperCapabilities('3.23', {
hasValue: true,
hasDestroyable: true,
});
constructor(public owner: Owner | undefined) {}
createHelper(
Helper: { new (owner: Owner | undefined, args: Arguments): TestHelper },
args: Arguments
) {
return new Helper(this.owner, args);
}
getValue(instance: TestHelper) {
return instance.value();
}
getDestroyable(instance: TestHelper) {
return instance;
}
getDebugName() {
return 'TEST_HELPER';
}
}
export abstract class TestHelper {
constructor(
owner: Owner,
public args: Arguments
) {
setOwner(this, owner);
registerDestructor(this, () => this.willDestroy());
}
abstract value(): unknown;
willDestroy() {}
}
setHelperManager((owner) => new TestHelperManager(owner), TestHelper);