@absolutejs/absolute 0.19.0-beta.853 → 0.19.0-beta.855
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/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/angular/index.js +50 -76
- package/dist/angular/index.js.map +3 -3
- package/dist/angular/server.js +51 -77
- package/dist/angular/server.js.map +3 -3
- package/dist/build.js +469 -652
- package/dist/build.js.map +6 -7
- package/dist/dev/client/hmrClient.ts +35 -6
- package/dist/index.js +490 -673
- package/dist/index.js.map +6 -7
- package/dist/src/dev/angular/fastHmrCompiler.d.ts +14 -1
- package/dist/src/dev/rebuildTrigger.d.ts +1 -0
- package/package.json +1 -1
- package/dist/dev/client/handlers/angular.ts +0 -684
- package/dist/dev/client/handlers/angularRuntime.ts +0 -415
- package/dist/src/dev/angular/editTypeDetection.d.ts +0 -8
|
@@ -1,415 +0,0 @@
|
|
|
1
|
-
import type {} from '../../../types/globals';
|
|
2
|
-
/* Angular HMR — Zoneless Runtime Preservation
|
|
3
|
-
DEV MODE ONLY — never included in production builds.
|
|
4
|
-
|
|
5
|
-
Runtime component patching via prototype swap and ɵcmp metadata swap.
|
|
6
|
-
State persists naturally via instance continuity — NO serialization.
|
|
7
|
-
|
|
8
|
-
Why state serialization was removed:
|
|
9
|
-
Angular component + service state lives on JS object instances.
|
|
10
|
-
Prototype swapping replaces method implementations without destroying
|
|
11
|
-
instances, so all state (properties, injected services, etc.) survives.
|
|
12
|
-
Serializing and reassigning state is fragile, lossy, and unnecessary.
|
|
13
|
-
|
|
14
|
-
Why zoneless requires manual tick():
|
|
15
|
-
With provideZonelessChangeDetection(), there is no Zone.js to
|
|
16
|
-
auto-trigger change detection. After swapping prototypes or templates,
|
|
17
|
-
we must explicitly call ApplicationRef.tick() to re-render.
|
|
18
|
-
|
|
19
|
-
Why this is safe in a multi-framework environment:
|
|
20
|
-
This module only touches Angular-specific globals (__ANGULAR_APP__,
|
|
21
|
-
__ANGULAR_HMR__). It never modifies document.body, React roots,
|
|
22
|
-
Vue instances, or Svelte components. The registry is keyed by
|
|
23
|
-
source file path, so name collisions across frameworks are impossible. */
|
|
24
|
-
|
|
25
|
-
type AngularComponentDefinition = {
|
|
26
|
-
providers?: unknown;
|
|
27
|
-
providersResolver?: unknown;
|
|
28
|
-
selectors?: unknown[];
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
type ComponentCtor = (abstract new (...args: never[]) => unknown) & {
|
|
32
|
-
ɵcmp?: AngularComponentDefinition;
|
|
33
|
-
ɵfac?: unknown;
|
|
34
|
-
ɵinj?: AngularComponentDefinition;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const isComponentCtor = (value: unknown): value is ComponentCtor =>
|
|
38
|
-
typeof value === 'function';
|
|
39
|
-
|
|
40
|
-
type RegistryEntry = {
|
|
41
|
-
liveCtor: ComponentCtor;
|
|
42
|
-
id: string;
|
|
43
|
-
registeredAt: number;
|
|
44
|
-
updateCount: number;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
type AngularHmrStats = {
|
|
48
|
-
readonly componentCount: number;
|
|
49
|
-
readonly updateCount: number;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/* The component registry MUST persist across chunk imports.
|
|
53
|
-
Each compiled page chunk inlines this `angularRuntime.ts` module — when
|
|
54
|
-
the HMR fast-patch dynamically `import()`s a new chunk, that chunk's
|
|
55
|
-
inlined runtime evaluates again. Without a window-level singleton, each
|
|
56
|
-
re-import would create a fresh `componentRegistry` Map, wipe out
|
|
57
|
-
prior registrations, and break subsequent fast-patches (the second
|
|
58
|
-
patch wouldn't find any registered components).
|
|
59
|
-
We anchor the registry on `globalThis.__ANGULAR_HMR_REGISTRY__` so every
|
|
60
|
-
chunk sees the same Map. */
|
|
61
|
-
type GlobalRegistryWindow = typeof globalThis & {
|
|
62
|
-
__ANGULAR_HMR_REGISTRY__?: Map<string, RegistryEntry>;
|
|
63
|
-
__ANGULAR_HMR_UPDATE_COUNT__?: { value: number };
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const globalScope = globalThis as GlobalRegistryWindow;
|
|
67
|
-
|
|
68
|
-
const componentRegistry: Map<string, RegistryEntry> =
|
|
69
|
-
globalScope.__ANGULAR_HMR_REGISTRY__ ??
|
|
70
|
-
(globalScope.__ANGULAR_HMR_REGISTRY__ = new Map<string, RegistryEntry>());
|
|
71
|
-
|
|
72
|
-
const updateCounter: { value: number } =
|
|
73
|
-
globalScope.__ANGULAR_HMR_UPDATE_COUNT__ ??
|
|
74
|
-
(globalScope.__ANGULAR_HMR_UPDATE_COUNT__ = { value: 0 });
|
|
75
|
-
|
|
76
|
-
/* Cheap structural fingerprint. Functions render as 'fn' (treated as
|
|
77
|
-
opaque — they change on every module reload but the static config
|
|
78
|
-
like provider tokens, useValue payloads, etc. is what we care
|
|
79
|
-
about). Objects walk depth-bounded with sorted keys so key order
|
|
80
|
-
doesn't cause spurious diffs. Used both for component-level
|
|
81
|
-
provider arrays and for page-level `routes`/`providers` exports. */
|
|
82
|
-
const fingerprint = (value: unknown, depth = 0): string => {
|
|
83
|
-
if (depth > 6) return '~deep~';
|
|
84
|
-
if (value === null) return 'null';
|
|
85
|
-
if (value === undefined) return 'undef';
|
|
86
|
-
if (typeof value === 'function') return 'fn';
|
|
87
|
-
if (typeof value === 'symbol') return value.toString();
|
|
88
|
-
if (Array.isArray(value)) {
|
|
89
|
-
return (
|
|
90
|
-
'[' + value.map((v) => fingerprint(v, depth + 1)).join(',') + ']'
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
if (typeof value === 'object') {
|
|
94
|
-
const obj = value as Record<string, unknown>;
|
|
95
|
-
const entries = Object.entries(obj)
|
|
96
|
-
.map(([k, v]): [string, string] => [k, fingerprint(v, depth + 1)])
|
|
97
|
-
.sort(([a], [b]) => a.localeCompare(b));
|
|
98
|
-
|
|
99
|
-
return '{' + entries.map(([k, v]) => `${k}:${v}`).join(',') + '}';
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return JSON.stringify(value);
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
const hasInjectorProviderChanges = (
|
|
106
|
-
oldCtor: ComponentCtor,
|
|
107
|
-
newCtor: ComponentCtor
|
|
108
|
-
) => {
|
|
109
|
-
if (oldCtor.ɵinj === undefined || newCtor.ɵinj === undefined) return false;
|
|
110
|
-
const oldP = oldCtor.ɵinj?.providers;
|
|
111
|
-
const newP = newCtor.ɵinj?.providers;
|
|
112
|
-
if (!Array.isArray(oldP) || !Array.isArray(newP)) return false;
|
|
113
|
-
|
|
114
|
-
return fingerprint(oldP) !== fingerprint(newP);
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
const hasComponentProviderChanges = (
|
|
118
|
-
oldCtor: ComponentCtor,
|
|
119
|
-
newCtor: ComponentCtor
|
|
120
|
-
) => {
|
|
121
|
-
if (!oldCtor.ɵcmp || !newCtor.ɵcmp) return false;
|
|
122
|
-
const oldResolver = oldCtor.ɵcmp.providersResolver;
|
|
123
|
-
const newResolver = newCtor.ɵcmp.providersResolver;
|
|
124
|
-
// Defined-ness flip — added/removed `providers: [...]` entirely.
|
|
125
|
-
if ((oldResolver === undefined) !== (newResolver === undefined))
|
|
126
|
-
return true;
|
|
127
|
-
if (typeof oldResolver !== 'function' || typeof newResolver !== 'function')
|
|
128
|
-
return false;
|
|
129
|
-
|
|
130
|
-
// `providersResolver` is the function the Angular compiler emits to
|
|
131
|
-
// merge a component's `providers` array into the element injector.
|
|
132
|
-
// Its source body inlines the provider tokens and useValue/useFactory
|
|
133
|
-
// references, so a change to the user's `providers: [...]` array
|
|
134
|
-
// produces a different function body. Comparing `toString()` catches
|
|
135
|
-
// content changes that the old length/defined-ness check missed —
|
|
136
|
-
// e.g. swapping `useValue: 'foo'` for `useValue: 'bar'` while
|
|
137
|
-
// keeping the array length identical.
|
|
138
|
-
return oldResolver.toString() !== newResolver.toString();
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const hasProviderChanges = (oldCtor: ComponentCtor, newCtor: ComponentCtor) => {
|
|
142
|
-
if (hasInjectorProviderChanges(oldCtor, newCtor)) return true;
|
|
143
|
-
if (hasComponentProviderChanges(oldCtor, newCtor)) return true;
|
|
144
|
-
|
|
145
|
-
return false;
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
const register = (id: string, ctor: unknown) => {
|
|
149
|
-
if (!id || !isComponentCtor(ctor)) return;
|
|
150
|
-
if (!componentRegistry.has(id)) {
|
|
151
|
-
componentRegistry.set(id, {
|
|
152
|
-
id,
|
|
153
|
-
liveCtor: ctor,
|
|
154
|
-
registeredAt: Date.now(),
|
|
155
|
-
updateCount: 0
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
const SKIP_STATIC_PROPS = [
|
|
161
|
-
'prototype',
|
|
162
|
-
'length',
|
|
163
|
-
'name',
|
|
164
|
-
'caller',
|
|
165
|
-
'arguments'
|
|
166
|
-
];
|
|
167
|
-
|
|
168
|
-
const swapPrototypeProp = (
|
|
169
|
-
liveCtor: ComponentCtor,
|
|
170
|
-
newProto: ComponentCtor,
|
|
171
|
-
prop: string
|
|
172
|
-
) => {
|
|
173
|
-
if (prop === 'constructor') return;
|
|
174
|
-
try {
|
|
175
|
-
const desc = Object.getOwnPropertyDescriptor(newProto, prop);
|
|
176
|
-
if (desc) Object.defineProperty(liveCtor.prototype, prop, desc);
|
|
177
|
-
} catch {
|
|
178
|
-
/* non-configurable */
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
const swapStaticProp = (
|
|
183
|
-
liveCtor: ComponentCtor,
|
|
184
|
-
newCtor: ComponentCtor,
|
|
185
|
-
prop: string
|
|
186
|
-
) => {
|
|
187
|
-
if (SKIP_STATIC_PROPS.includes(prop)) return true;
|
|
188
|
-
try {
|
|
189
|
-
const desc = Object.getOwnPropertyDescriptor(newCtor, prop);
|
|
190
|
-
if (!desc) return true;
|
|
191
|
-
if (!desc.configurable) return prop !== 'ɵcmp' && prop !== 'ɵfac';
|
|
192
|
-
Object.defineProperty(liveCtor, prop, desc);
|
|
193
|
-
|
|
194
|
-
return true;
|
|
195
|
-
} catch {
|
|
196
|
-
return prop !== 'ɵcmp' && prop !== 'ɵfac';
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
const patchConstructor = (entry: RegistryEntry, newCtor: ComponentCtor) => {
|
|
201
|
-
const { liveCtor } = entry;
|
|
202
|
-
|
|
203
|
-
const newProto = newCtor.prototype;
|
|
204
|
-
Object.getOwnPropertyNames(newProto).forEach((prop) => {
|
|
205
|
-
swapPrototypeProp(liveCtor, newProto, prop);
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
const allPatched = Object.getOwnPropertyNames(newCtor).every((prop) =>
|
|
209
|
-
swapStaticProp(liveCtor, newCtor, prop)
|
|
210
|
-
);
|
|
211
|
-
|
|
212
|
-
if (!allPatched) {
|
|
213
|
-
throw new Error('Cannot patch non-configurable Angular metadata');
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
updateCounter.value++;
|
|
217
|
-
entry.updateCount++;
|
|
218
|
-
entry.registeredAt = Date.now();
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
/* The fast-patch swap of `ɵcmp` and prototype methods doesn't mark
|
|
222
|
-
live OnPush components as dirty — `applicationRef.tick()` alone
|
|
223
|
-
only checks views that are already marked dirty. So a template
|
|
224
|
-
edit on an OnPush component would silently fail to render until
|
|
225
|
-
the user clicked something that triggered a markForCheck.
|
|
226
|
-
We collect every successfully-patched ctor here, then `refresh()`
|
|
227
|
-
walks the DOM for each ctor's selector, gets the live instance via
|
|
228
|
-
the `ng` debug API, and calls `applyChanges` on it (which marks
|
|
229
|
-
the view dirty AND runs CD on its subtree). */
|
|
230
|
-
const pendingFastPatchRefresh: Set<ComponentCtor> = new Set();
|
|
231
|
-
|
|
232
|
-
type AngularDebugWindow = Window & {
|
|
233
|
-
ng?: {
|
|
234
|
-
applyChanges?: (component: unknown) => void;
|
|
235
|
-
getComponent?: (element: Element) => unknown;
|
|
236
|
-
};
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
const componentTagSelectors = (ctor: ComponentCtor): string[] => {
|
|
240
|
-
const selectors = ctor.ɵcmp?.selectors;
|
|
241
|
-
if (!Array.isArray(selectors)) return [];
|
|
242
|
-
const tags: string[] = [];
|
|
243
|
-
for (const tuple of selectors) {
|
|
244
|
-
if (!Array.isArray(tuple)) continue;
|
|
245
|
-
const head = tuple[0];
|
|
246
|
-
// Component selectors lead with the tag name (a hyphenated
|
|
247
|
-
// element name); attribute selectors lead with `''`. Skip the
|
|
248
|
-
// attribute case — those are directives, not OnPush views.
|
|
249
|
-
if (typeof head === 'string' && head.includes('-')) tags.push(head);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
return tags;
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
const markPatchedDirty = (ctor: ComponentCtor) => {
|
|
256
|
-
const ng = (window as AngularDebugWindow).ng;
|
|
257
|
-
if (!ng?.getComponent || !ng?.applyChanges) return;
|
|
258
|
-
for (const tag of componentTagSelectors(ctor)) {
|
|
259
|
-
document.querySelectorAll(tag).forEach((el) => {
|
|
260
|
-
try {
|
|
261
|
-
const instance = ng.getComponent?.(el);
|
|
262
|
-
if (instance) ng.applyChanges?.(instance);
|
|
263
|
-
} catch {
|
|
264
|
-
/* dev-only debug API — ignore failures */
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
const applyUpdate = (id: string, newCtor: unknown) => {
|
|
271
|
-
if (!isComponentCtor(newCtor)) return false;
|
|
272
|
-
|
|
273
|
-
const entry = componentRegistry.get(id);
|
|
274
|
-
if (!entry) {
|
|
275
|
-
register(id, newCtor);
|
|
276
|
-
|
|
277
|
-
return true;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const { liveCtor } = entry;
|
|
281
|
-
if (liveCtor === newCtor) return true;
|
|
282
|
-
|
|
283
|
-
if (hasProviderChanges(liveCtor, newCtor)) {
|
|
284
|
-
console.warn(
|
|
285
|
-
'[HMR] Angular provider change detected for',
|
|
286
|
-
id,
|
|
287
|
-
'→ full reload'
|
|
288
|
-
);
|
|
289
|
-
|
|
290
|
-
return false;
|
|
291
|
-
}
|
|
292
|
-
if (newCtor.ɵcmp === undefined && liveCtor.ɵcmp !== undefined) {
|
|
293
|
-
console.warn(
|
|
294
|
-
'[HMR] New constructor missing ɵcmp for',
|
|
295
|
-
id,
|
|
296
|
-
'→ full reload'
|
|
297
|
-
);
|
|
298
|
-
|
|
299
|
-
return false;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
try {
|
|
303
|
-
patchConstructor(entry, newCtor);
|
|
304
|
-
// Queue this ctor for `refresh()` to mark its live instances
|
|
305
|
-
// dirty — the patch swapped metadata in place, but OnPush
|
|
306
|
-
// components need an explicit markForCheck to re-render.
|
|
307
|
-
// `liveCtor` is the on-page constructor (we patched into it);
|
|
308
|
-
// we use that for selector lookup since the swap may have
|
|
309
|
-
// updated `ɵcmp` on `liveCtor` itself.
|
|
310
|
-
pendingFastPatchRefresh.add(liveCtor);
|
|
311
|
-
|
|
312
|
-
return true;
|
|
313
|
-
} catch (err) {
|
|
314
|
-
console.error('[HMR] Angular runtime patch failed for', id, ':', err);
|
|
315
|
-
|
|
316
|
-
return false;
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
const refresh = () => {
|
|
321
|
-
if (!window.__ANGULAR_APP__) return;
|
|
322
|
-
// Mark every live instance of every patched component dirty before
|
|
323
|
-
// ticking. `tick()` alone wouldn't re-render OnPush components,
|
|
324
|
-
// since they only re-check on `markForCheck`. `applyChanges` marks
|
|
325
|
-
// the view dirty and runs CD on its subtree — covers both OnPush
|
|
326
|
-
// and Default change-detection components correctly.
|
|
327
|
-
for (const ctor of pendingFastPatchRefresh) {
|
|
328
|
-
markPatchedDirty(ctor);
|
|
329
|
-
}
|
|
330
|
-
pendingFastPatchRefresh.clear();
|
|
331
|
-
try {
|
|
332
|
-
window.__ANGULAR_APP__.tick();
|
|
333
|
-
} catch (err) {
|
|
334
|
-
console.warn('[HMR] Angular tick() failed after patch:', err);
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
|
-
|
|
338
|
-
const angularHmrStats: AngularHmrStats = {
|
|
339
|
-
get componentCount() {
|
|
340
|
-
return componentRegistry.size;
|
|
341
|
-
},
|
|
342
|
-
get updateCount() {
|
|
343
|
-
return updateCounter.value;
|
|
344
|
-
}
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
const getAngularHmrStats = () => angularHmrStats;
|
|
348
|
-
|
|
349
|
-
/* Page-level export fingerprints — detect when `routes` or `providers`
|
|
350
|
-
change in a page file so the HMR fast-patch can fall back to a full
|
|
351
|
-
re-bootstrap. Without this, a component-level fast-patch silently
|
|
352
|
-
succeeds while the route/provider change is left dangling — the
|
|
353
|
-
running router/injector still uses the values from the initial
|
|
354
|
-
bootstrap. The page chunk template calls `recordPageExports` on every
|
|
355
|
-
evaluation (initial bootstrap and HMR re-imports); the fast-patch
|
|
356
|
-
handler then checks `hasPageExportsChanged` to decide whether to
|
|
357
|
-
force a full re-bootstrap.
|
|
358
|
-
Function references are treated as opaque — they change on every
|
|
359
|
-
module reload but the static config (`path`, `pathMatch`, provider
|
|
360
|
-
token, useValue, etc.) is what we care about. */
|
|
361
|
-
|
|
362
|
-
type PageFingerprint = {
|
|
363
|
-
routes: string | null;
|
|
364
|
-
providers: string | null;
|
|
365
|
-
};
|
|
366
|
-
|
|
367
|
-
type PageExportRecord = {
|
|
368
|
-
current: PageFingerprint;
|
|
369
|
-
previous: PageFingerprint | null;
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
const pageExportRecords = ((
|
|
373
|
-
globalThis as { __ABS_HMR_PAGE_EXPORTS__?: Map<string, PageExportRecord> }
|
|
374
|
-
).__ABS_HMR_PAGE_EXPORTS__ ??= new Map<string, PageExportRecord>());
|
|
375
|
-
|
|
376
|
-
const recordPageExports = (
|
|
377
|
-
sourceId: string,
|
|
378
|
-
routes: unknown,
|
|
379
|
-
providers: unknown
|
|
380
|
-
) => {
|
|
381
|
-
const next: PageFingerprint = {
|
|
382
|
-
routes: routes === undefined ? null : fingerprint(routes),
|
|
383
|
-
providers: providers === undefined ? null : fingerprint(providers)
|
|
384
|
-
};
|
|
385
|
-
const existing = pageExportRecords.get(sourceId);
|
|
386
|
-
pageExportRecords.set(sourceId, {
|
|
387
|
-
current: next,
|
|
388
|
-
previous: existing?.current ?? null
|
|
389
|
-
});
|
|
390
|
-
};
|
|
391
|
-
|
|
392
|
-
const hasPageExportsChanged = (sourceId: string): boolean => {
|
|
393
|
-
const record = pageExportRecords.get(sourceId);
|
|
394
|
-
if (!record || !record.previous) return false;
|
|
395
|
-
|
|
396
|
-
return (
|
|
397
|
-
record.previous.routes !== record.current.routes ||
|
|
398
|
-
record.previous.providers !== record.current.providers
|
|
399
|
-
);
|
|
400
|
-
};
|
|
401
|
-
|
|
402
|
-
export const installAngularHMRRuntime = () => {
|
|
403
|
-
if (typeof window === 'undefined') return;
|
|
404
|
-
window.__ANGULAR_HMR__ = {
|
|
405
|
-
applyUpdate,
|
|
406
|
-
getStats: getAngularHmrStats,
|
|
407
|
-
hasPageExportsChanged,
|
|
408
|
-
recordPageExports,
|
|
409
|
-
refresh,
|
|
410
|
-
register,
|
|
411
|
-
getRegistry: () => componentRegistry
|
|
412
|
-
};
|
|
413
|
-
};
|
|
414
|
-
|
|
415
|
-
installAngularHMRRuntime();
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export type AngularEditType = 'template' | 'style-component' | 'class-component' | 'service-method-only' | 'service-with-side-effects' | 'route' | 'reboot';
|
|
2
|
-
export type AngularEditClassification = {
|
|
3
|
-
type: AngularEditType;
|
|
4
|
-
reason: string;
|
|
5
|
-
sourceFile: string;
|
|
6
|
-
};
|
|
7
|
-
export declare const classifyAngularEdit: (file: string) => AngularEditClassification;
|
|
8
|
-
export declare const collapseClassifications: (classifications: AngularEditClassification[]) => AngularEditClassification;
|