@dynamicforms/vue-forms 3.0.0-alpha.1 → 3.0.0-alpha.3

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/index.d.ts CHANGED
@@ -117,10 +117,21 @@ declare type ActionExecutor = (field: FieldBase, supr: FieldActionExecute, ...pa
117
117
  */
118
118
  export declare class ActionsMap {
119
119
  /**
120
- * Every action registered here, in registration order. Unregistering replaces the array instead of modifying it,
121
- * so a run in progress finishes on the array it started with and the removal takes effect from the next trigger.
120
+ * Every action registered here, in registration order. Registering and unregistering replace the array instead of
121
+ * modifying it, so a run in progress finishes on the array it started with, the change takes effect from the next
122
+ * trigger, and an array read through `registrations` never changes.
122
123
  */
123
124
  private actions;
125
+ /**
126
+ * The registered actions, in registration order. The array is not modified later, so it records the
127
+ * registrations at the time of the read; `restore()` reinstates them.
128
+ */
129
+ get registrations(): readonly FieldActionBase[];
130
+ /**
131
+ * Replaces the registered actions with `registrations`, an array `registrations` returned earlier. The order of
132
+ * the handlers and every duplicate registration are restored with it.
133
+ */
134
+ restore(registrations: readonly FieldActionBase[]): void;
124
135
  /**
125
136
  * Registers `action`. It becomes the outermost handler of its identifier, or, if `before` is given, is inserted
126
137
  * at the position of `before`, so `before` wraps it and calls it through `supr`. This adds an action to an
@@ -128,6 +139,8 @@ export declare class ActionsMap {
128
139
  * same identifier, and a TypeError for an `ErrorPolicy` naming an origin another one registered here names.
129
140
  */
130
141
  register(action: FieldActionBase, before?: FieldActionBase): void;
142
+ /** A copy of `actions` with `action` inserted at `index`. */
143
+ private static inserted;
131
144
  /** Unregisters `action` and returns whether it was registered here. */
132
145
  unregister(action: FieldActionBase): boolean;
133
146
  /** True if any action is registered under `identifier`. */
@@ -253,16 +266,23 @@ declare class CompareTo<T = any> extends Validator {
253
266
  */
254
267
  private readonly registrations;
255
268
  /**
256
- * The elements this validator has installed its listener on. A binding of such an element has the listener too
257
- * (a binding uses the actions of its declaration), so the declaration is checked as well, and a list of N rows
258
- * installs one listener, not N.
269
+ * The declarations of the elements this validator has installed its listener on. A registration goes into the map
270
+ * of the element's declaration, which every binding of it uses, so a list of N rows installs one listener, not N.
259
271
  */
260
272
  private readonly listening;
261
273
  /**
262
- * The declarations of the fields this validator was registered on. One entry covers every binding of such a
274
+ * The declarations of the fields this validator is registered on. One entry covers every binding of such a
263
275
  * field, so a change of a compared element finds the fields of its record without this set holding every row.
276
+ * They are held weakly: the listener on the compared element keeps this validator reachable, and a form dropped
277
+ * without unregistering the validator is released all the same.
264
278
  */
265
279
  private readonly declarations;
280
+ /**
281
+ * The listener on the compared elements, one instance for all of them. It is removed when the validator is taken
282
+ * off its last declaration, or, once its declarations are collected, when an element it is registered on asks it
283
+ * to release itself.
284
+ */
285
+ private readonly relay;
266
286
  constructor(otherField: CompareToTarget, isValidComparison: (myValue: T, otherValue: T) => boolean, options?: ValidationErrorOptions);
267
287
  /** The element `field` is compared against, within the record `field` belongs to. */
268
288
  private resolve;
@@ -272,6 +292,8 @@ declare class CompareTo<T = any> extends Validator {
272
292
  * declaration applies to that row; it re-runs only this validator, not the whole chain.
273
293
  */
274
294
  private listenOn;
295
+ /** Removes the listener from every compared element; a rollback restores it and the record of the elements. */
296
+ private stopListening;
275
297
  boundToBinding(binding: FieldBase): void;
276
298
  private comparisonState;
277
299
  protected newBindingState(): CompareToBindingState<T>;
@@ -304,9 +326,10 @@ export declare class ConditionalStatementAction extends ValueChangedAction {
304
326
  private readonly statement;
305
327
  private readonly conditionalExecutor;
306
328
  /**
307
- * The declarations of the elements this action was registered on. It holds declarations, not the elements, so one
329
+ * The declarations of the elements this action is registered on. It holds declarations, not the elements, so one
308
330
  * entry covers every row of a list; a result is applied to the element that corresponds to the declaration within
309
- * the record the change happened in.
331
+ * the record the change happened in. They are held weakly: the relay on a field the statement reads keeps this
332
+ * action reachable, and a form dropped without unregistering the action is released all the same.
310
333
  */
311
334
  private readonly declarations;
312
335
  /**
@@ -318,13 +341,16 @@ export declare class ConditionalStatementAction extends ValueChangedAction {
318
341
  constructor(statement: Statement, executorFn: ConditionalExecutorFn);
319
342
  /**
320
343
  * The listener on the fields the statement reads. The constructor installs it; it is removed when the action is
321
- * taken off its last element and installed again when the action is next registered.
344
+ * taken off its last element or its elements are collected, and installed again when the action is next
345
+ * registered.
322
346
  */
323
347
  private readonly relay;
324
- /** The number of elements the action is registered on; the relay is removed when it drops to zero. */
325
- private registered;
326
348
  private listening;
349
+ /** Whether the action has been registered on an element; until then the relay waits for its first element. */
350
+ private bound;
327
351
  private listen;
352
+ /** Removes the relay from the fields the statement reads; a rollback restores it with the flag. */
353
+ private stopListening;
328
354
  static get classIdentifier(): symbol;
329
355
  get eager(): boolean;
330
356
  boundToBinding(binding: FieldBase): void;
@@ -576,8 +602,6 @@ declare interface ElementSlots<T = any> {
576
602
  parent: Container | undefined;
577
603
  /** the name the containing Group holds this element under; undefined for a List row */
578
604
  fieldName: string | undefined;
579
- /** generation of the validators attached to the element; clearValidators() raises it */
580
- validationEpoch: number;
581
605
  /**
582
606
  * The element's extended properties, typed by the element's X parameter. A write replaces the object instead of
583
607
  * modifying it, so an effect that read the slot re-runs on the write, and a rollback restores the object the
@@ -631,15 +655,24 @@ export declare class EnabledChangingAction extends FieldActionBase {
631
655
  execute(field: FieldBase, supr: FieldActionExecute, newValue: boolean, oldValue: boolean): boolean;
632
656
  }
633
657
 
658
+ /**
659
+ * The namespace of the error codes this library declares. A code the library raises is `${ERROR_NAMESPACE}.<code>`,
660
+ * such as `vue-forms.required`.
661
+ */
662
+ export declare const ERROR_NAMESPACE = "vue-forms";
663
+
634
664
  /**
635
665
  * The content of an error: what failed, the values it failed with, an English sentence describing it, and its
636
666
  * origin. An error the application builds from a server's response has the same content, so a renderer converts
637
667
  * validator and server errors to text with one function.
638
668
  */
639
669
  export declare interface ErrorDescription {
640
- /** Machine-readable identifier of what failed, in snake_case. */
670
+ /**
671
+ * Machine-readable identifier of what failed: `<namespace>.<code>`, such as `vue-forms.min_value`. The namespace
672
+ * names the package that declared the code.
673
+ */
641
674
  readonly code: string;
642
- /** The values of the failure, such as `minValue` for `min_value`. */
675
+ /** The values of the failure, such as `minValue` for `vue-forms.min_value`. */
643
676
  readonly params: Readonly<Record<string, unknown>>;
644
677
  /** The failure in English, plain text, with `params` substituted. */
645
678
  readonly detail: string;
@@ -1112,10 +1145,7 @@ export declare abstract class FieldBase<T = any, X extends object = Extras> {
1112
1145
  protected get boundActions(): ActionsMap | undefined;
1113
1146
  /** Records that `binding` was made from this element, so a later registration can reach it. */
1114
1147
  protected noteBinding(binding: FieldBase): void;
1115
- /**
1116
- * The live bindings made from this element's declaration, and the declaration itself. Dead references are removed
1117
- * when found, so the set does not grow over the life of a long-lived declaration.
1118
- */
1148
+ /** The live bindings made from this element's declaration and the declaration; removes the dead references. */
1119
1149
  protected get boundElements(): FieldBase[];
1120
1150
  /**
1121
1151
  * The map registrations go into: the declaration's. The map is created on the first registration and assigned to
@@ -1185,8 +1215,9 @@ export declare abstract class FieldBase<T = any, X extends object = Extras> {
1185
1215
  * Makes this element the container of `child`: it sets the back-reference, records the name a Group holds the
1186
1216
  * child under, and adds the child to the invalid count. An element belongs to one container at a time, so a
1187
1217
  * child that already has a parent throws a TypeError; releaseChild() removes the link, after which the element
1188
- * can be taken by another container. The child's state is private to FieldBase, so a container writes the two
1189
- * slots through this method.
1218
+ * can be taken by another container. A container cannot take itself or a container above it, which also throws a
1219
+ * TypeError: the parent links would form a cycle, and a walk up them would not end. The child's state is private
1220
+ * to FieldBase, so a container writes the two slots through this method.
1190
1221
  */
1191
1222
  protected takeChild(child: FieldBase, fieldName?: string): void;
1192
1223
  /** Adds a child to this element's invalid count; a container calls it after setting the child's parent link. */
@@ -1399,19 +1430,19 @@ export declare abstract class FieldBase<T = any, X extends object = Extras> {
1399
1430
  */
1400
1431
  unregisterAction(action: FieldActionBase): boolean;
1401
1432
  /**
1402
- * Binds a newly registered `action` to the existing bindings and registers an undo for a rollback. The
1403
- * registration is not in the state slots the snapshot covers, so it registers its own undo.
1433
+ * Registers `action` on the declaration, binds it to the existing bindings and registers an undo for a rollback.
1434
+ * The registration is not in the state slots the snapshot covers, so it registers its own undo, before any call
1435
+ * that can throw: a registration that fails part way is undone with the transaction.
1436
+ */
1437
+ private register;
1438
+ /**
1439
+ * Asks the actions of `actions` to release themselves if abandoned (see `ReleaseIfAbandoned`), if a minute or more
1440
+ * has passed since the last time. A map is checked only when an action is registered on it, with no timer.
1404
1441
  */
1405
- private registered;
1442
+ private releaseAbandoned;
1406
1443
  triggerAction<T2 extends FieldActionBase>(actionClass: (abstract new (...args: any[]) => T2) & {
1407
1444
  classIdentifier: symbol;
1408
1445
  }, ...params: any[]): any;
1409
- /**
1410
- * Generation counter of the validators attached to this field. A Validator reads it when a run starts and drops
1411
- * a result whose epoch no longer matches, so a validation still in flight when clearValidators() is called
1412
- * cannot push an error onto a field that no longer has the validator that produced it.
1413
- */
1414
- get [ValidationEpoch](): number;
1415
1446
  clearValidators(): void;
1416
1447
  }
1417
1448
 
@@ -1521,6 +1552,7 @@ declare namespace Form {
1521
1552
  ListItemInput,
1522
1553
  List,
1523
1554
  NullableList,
1555
+ ERROR_NAMESPACE,
1524
1556
  ErrorPolicies,
1525
1557
  ErrorPolicy,
1526
1558
  ErrorPolicyRule,
@@ -1591,6 +1623,8 @@ export declare class Group<T extends GenericFieldsInterface = GenericFieldsInter
1591
1623
  private static setEntry;
1592
1624
  /** Removes one entry from the member map. */
1593
1625
  private static dropEntry;
1626
+ /** Replaces the entries of the member map with `entries`, in their order. */
1627
+ private static restoreEntries;
1594
1628
  private static isValidFields;
1595
1629
  /**
1596
1630
  * Builds a group from plain data, so that its `fullValue` is `data`: a plain object becomes a `Group`, an array a
@@ -1727,7 +1761,7 @@ declare class InAllowedValues<T = any> extends Validator {
1727
1761
  /**
1728
1762
  * Installs `plugin` for every element, including the ones already built: a hook runs on the next write. A plugin
1729
1763
  * installed twice runs twice. Returns a function that uninstalls it; values stored while it was installed are kept
1730
- * as they are.
1764
+ * as they are. Where `setup` throws, the plugin is not installed and the exception is rethrown.
1731
1765
  */
1732
1766
  export declare function installPlugin(plugin: Plugin_2): () => void;
1733
1767
 
@@ -2248,7 +2282,7 @@ declare class Transaction {
2248
2282
  /**
2249
2283
  * Registers work that runs after the transaction commits, and not at all if it is rolled back. An operation uses
2250
2284
  * it to defer a step that cannot be undone (for example, cancelling work in flight) until its change is
2251
- * committed.
2285
+ * committed. The work runs after the transaction is closed, so a write it makes opens a transaction of its own.
2252
2286
  */
2253
2287
  whenCommitted(work: () => void): void;
2254
2288
  /**
@@ -2273,6 +2307,12 @@ declare class Transaction {
2273
2307
  * is dirty.
2274
2308
  */
2275
2309
  commit(): void;
2310
+ /**
2311
+ * Runs the work registered with whenCommitted, then the `onCommit` hooks. It is called after the transaction is
2312
+ * closed, so a write made here opens a transaction of its own and is announced, and an exception does not roll
2313
+ * back the committed change. Every step runs; the first exception thrown is rethrown after the last one.
2314
+ */
2315
+ settle(): void;
2276
2316
  /**
2277
2317
  * The dirty participants a pass visits, one bucket per nesting depth; within a depth they keep enrolment order.
2278
2318
  * A nesting depth is a small integer, so bucketing replaces a comparison sort: a whole-list assignment enrols one
@@ -2356,9 +2396,6 @@ declare interface TxStructuralEvent {
2356
2396
  index: number;
2357
2397
  }
2358
2398
 
2359
- /** Key of the `FieldBase` getter for the generation counter of its validators; the package does not export it. */
2360
- declare const ValidationEpoch: unique symbol;
2361
-
2362
2399
  /**
2363
2400
  * An error on an element. It is data: the library does not render it. A renderer chooses the text for `code` and
2364
2401
  * `params` and falls back to `detail`.
@@ -2369,8 +2406,8 @@ export declare class ValidationError implements ErrorDescription {
2369
2406
  readonly detail: string;
2370
2407
  private readonly statedOrigin?;
2371
2408
  /**
2372
- * @param code Machine-readable identifier of what failed, in snake_case.
2373
- * @param params The values of the failure, such as `minValue` for `min_value`.
2409
+ * @param code Machine-readable identifier of what failed, `<namespace>.<code>`. Stored as given.
2410
+ * @param params The values of the failure, such as `minValue` for `vue-forms.min_value`.
2374
2411
  * @param detail The failure in English, plain text. Stored as given.
2375
2412
  * @param statedOrigin The origin of the error, if its author sets it; see `origin`.
2376
2413
  */
@@ -2394,11 +2431,14 @@ export declare class ValidationError implements ErrorDescription {
2394
2431
  * renderer has a text for that code.
2395
2432
  */
2396
2433
  declare type ValidationErrorOptions = {
2397
- /** The error's `code`. Defaults to the validator's own, such as `required`. */
2434
+ /**
2435
+ * The error's `code`, used as given. Defaults to the validator's own, such as `vue-forms.required`. The
2436
+ * application prefixes its own codes with a namespace of its own.
2437
+ */
2398
2438
  code?: string;
2399
2439
  detail?: never;
2400
2440
  } | {
2401
- /** The error's `code`. */
2441
+ /** The error's `code`, used as given. */
2402
2442
  code: string;
2403
2443
  /** The error's English `detail`, plain text. `{name}` placeholders are replaced with the error's `params`. */
2404
2444
  detail?: string;
@@ -2440,13 +2480,15 @@ declare class Validator<T = any> extends ValueChangedAction {
2440
2480
  * remaining validators. Otherwise the field would stay invalid on an error no validator removes.
2441
2481
  *
2442
2482
  * A run in flight over the field is cancelled when the removal is committed, not earlier: a rollback restores the
2443
- * validator and its epoch, and the run, still active, then applies its result. Cancelling at the removal would
2444
- * leave the field valid over an unchecked value after a rollback.
2483
+ * validator, and the run, still active, then applies its result. Cancelling at the removal would leave the field
2484
+ * valid over an unchecked value after a rollback. A run started after the removal, by registering the validator
2485
+ * again in the same transaction, is not cancelled.
2445
2486
  */
2446
2487
  unregisterFrom(field: FieldBase): void;
2447
2488
  /**
2448
- * Cancels the asynchronous run in flight over `field`, if any. It is called after the validator is removed from
2449
- * the field: the field's validation epoch has changed, so the run's result is discarded and its signal aborts.
2489
+ * Cancels the asynchronous run in flight over `field`, if any. It is called once the validator's removal from the
2490
+ * field is committed: the run number advances, so the run's result is discarded and its signal aborts. The other
2491
+ * validators of the field keep their runs.
2450
2492
  */
2451
2493
  protected abandonRun(field: FieldBase): void;
2452
2494
  /**
@@ -2463,7 +2505,8 @@ declare class Validator<T = any> extends ValueChangedAction {
2463
2505
  protected newBindingState(): ValidatorBindingState;
2464
2506
  /**
2465
2507
  * Returns the error a built-in validator reports: `code` and `detail` from `options` if set, the validator's own
2466
- * otherwise, with `params` substituted into the detail.
2508
+ * otherwise, with `params` substituted into the detail. Both codes are used as given: a built-in validator passes
2509
+ * its own code as `vue-forms.<code>`, and a subclass of the application passes a code in a namespace of its own.
2467
2510
  */
2468
2511
  protected errorFor(options: ValidationErrorOptions | undefined, code: string, detail: string, params: Record<string, unknown>): ValidationError;
2469
2512
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dynamicforms/vue-forms",
3
3
  "private": false,
4
- "version": "3.0.0-alpha.1",
4
+ "version": "3.0.0-alpha.3",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "description": "Reactive forms and application state for Vue.js: validation, rules between fields, transactions and lists. UI-agnostic and TypeScript-first.",
@@ -28,8 +28,7 @@
28
28
  "build": "vite build",
29
29
  "prepack": "npm run build",
30
30
  "test": "vitest run --coverage",
31
- "lint": "eslint src --fix && vue-tsc --noEmit",
32
- "lint:ci": "eslint src && vue-tsc --noEmit",
31
+ "lint": "node scripts/lint.mjs",
33
32
  "docs:dev": "npm run docs:dev -w docs",
34
33
  "docs:build": "npm run docs:build -w docs",
35
34
  "docs:preview": "npm run docs:preview -w docs"
@@ -77,6 +76,7 @@
77
76
  "@vue/test-utils": "^2.2.4",
78
77
  "@vue/tsconfig": "^0.7.0",
79
78
  "baseline-browser-mapping": "^2.8.31",
79
+ "esbuild": "^0.28.2",
80
80
  "eslint": "^10.4.0",
81
81
  "eslint-config-prettier": "^10.1.8",
82
82
  "eslint-config-velis": "^3.0.0",
@@ -86,6 +86,7 @@
86
86
  "eslint-plugin-unicorn": "^73.0.0",
87
87
  "eslint-plugin-vue": "^10.10.0",
88
88
  "jsdom": "^26.0.0",
89
+ "markdownlint-cli2": "^0.18.1",
89
90
  "prettier": "^3.9.6",
90
91
  "rollup-plugin-visualizer": "^5.14.0",
91
92
  "typescript": "^5",
package/readme.md CHANGED
@@ -60,7 +60,8 @@ npm install @dynamicforms/vue-forms
60
60
  ```
61
61
 
62
62
  The package is ESM-only and requires Node 22 or newer. A CommonJS consumer reaches it through `require()` of an ES
63
- module, which Node supports without a flag from 22.12; on 22.0–22.11 it needs `--experimental-require-module`. Type definitions ship with the build. The package ships no components and no styles.
63
+ module, which Node supports without a flag from 22.12; on 22.0–22.11 it needs `--experimental-require-module`. Type
64
+ definitions ship with the build. The package ships no components and no styles.
64
65
 
65
66
  ## Basic Usage Example
66
67
 
@@ -185,7 +186,7 @@ import { Field, Group, Validators } from '@dynamicforms/vue-forms';
185
186
  const validatedForm = new Group({
186
187
  // Required field
187
188
  username: new Field({
188
- validators: [new Validators.Required({ code: 'username_required', detail: 'Username is required' })]
189
+ validators: [new Validators.Required({ code: 'app.username_required', detail: 'Username is required' })]
189
190
  }),
190
191
 
191
192
  // Email validation with pattern
@@ -193,7 +194,7 @@ const validatedForm = new Group({
193
194
  validators: [
194
195
  new Validators.Pattern(
195
196
  /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
196
- { code: 'invalid_email', detail: 'Please enter a valid email address' }
197
+ { code: 'app.invalid_email', detail: 'Please enter a valid email address' }
197
198
  )
198
199
  ]
199
200
  }),
@@ -202,7 +203,7 @@ const validatedForm = new Group({
202
203
  age: new Field({
203
204
  value: 25,
204
205
  validators: [
205
- new Validators.ValueInRange(18, 100, { code: 'age_range', detail: 'Age must be between {minValue} and {maxValue}' })
206
+ new Validators.ValueInRange(18, 100, { code: 'app.age_range', detail: 'Age must be between {minValue} and {maxValue}' })
206
207
  ]
207
208
  }),
208
209
 
@@ -216,7 +217,7 @@ const validatedForm = new Group({
216
217
  // Text length validation
217
218
  bio: new Field({
218
219
  validators: [
219
- new Validators.LengthInRange(10, 200, { code: 'bio_length', detail: 'Bio must be between 10 and 200 characters' })
220
+ new Validators.LengthInRange(10, 200, { code: 'app.bio_length', detail: 'Bio must be between 10 and 200 characters' })
220
221
  ]
221
222
  })
222
223
  });
@@ -227,10 +228,12 @@ invalid immediately. `field.touched` determines when the UI shows the errors. `R
227
228
  measuring it, so a value of only spaces counts as empty; `new Validators.Required({ trim: false })` keeps spaces as
228
229
  part of the value.
229
230
 
230
- An error is data: a `code` (`required`, `pattern`, `min_length`, …), the `params` it failed with, and an English
231
- `detail`. The library does not render it. The application, or a UI library such as `@dynamicforms/vuetify-inputs`,
232
- converts it into text, translated by its code. A validator's last argument, `{ code, detail }`, replaces the
233
- validator's default code and English detail.
231
+ An error is data: a `code` (`vue-forms.required`, `vue-forms.pattern`, `vue-forms.min_length`, …), the `params` it
232
+ failed with, and an English `detail`. A code is `<namespace>.<code>`; the library's namespace is `vue-forms`,
233
+ exported as `ERROR_NAMESPACE`. The library does not render an error. The application, or a UI library such as
234
+ `@dynamicforms/vuetify-inputs`, converts it into text, translated by its code. A validator's last argument,
235
+ `{ code, detail }`, replaces the validator's default code and English detail; the library uses that code as given,
236
+ and the application prefixes its own codes with a namespace of its own.
234
237
 
235
238
  A validation function may return a `Promise`; `field.validating` is `true` while it runs, and only the newest run
236
239
  determines the result. [Asynchronous validation](https://docs.velis.si/dynamicforms/vue-forms/api/validators#asynchronous-validation)
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry-_vVZW3p9.js","names":[],"sources":["../../src/plugins/devtools/registry.ts"],"sourcesContent":["import { type ComponentInternalInstance, getCurrentInstance, getCurrentScope, onScopeDispose } from 'vue';\n\nimport type { FieldBase } from '../../field-base';\nimport type { PluginContext } from '../../plugins';\n\n/** Which elements the devtools list: every root element except the hidden ones, or only the described ones. */\nexport type DevtoolsRegistration = 'opt-out' | 'opt-in';\n\n/** What an application states about an element for the devtools. */\nexport interface StateDescription {\n /** The name the devtools show; defaults to the element's class and a number. */\n name?: string;\n /** The file the element is defined in; defaults to the file of the code that constructed it. */\n file?: string;\n}\n\n/** What the registry knows about one element. */\nexport interface Entry {\n id: string;\n element: WeakRef<FieldBase>;\n /** the stack at construction; its text is built on the first read, when the devtools show the entry */\n created?: Error;\n /** the component whose setup constructed the element */\n instance?: WeakRef<ComponentInternalInstance>;\n description: StateDescription;\n hidden: boolean;\n described: boolean;\n}\n\nconst entries = new Map<string, Entry>();\nconst byElement = new WeakMap<FieldBase, Entry>();\nlet nextId = 1;\nlet registration: DevtoolsRegistration = 'opt-out';\nlet enabled = true;\nlet changed: (() => void) | undefined;\nlet context: PluginContext | undefined;\n\n/** Records the context the devtools plugin received; it tells a binding or an item template from a root. */\nexport function useContext(installed: PluginContext): void {\n context = installed;\n}\n\n/** Called by the devtools plugin; runs after a change the devtools show. */\nexport function onRegistryChanged(listener: () => void): void {\n changed = listener;\n}\n\n/**\n * Records an element at construction: the component that constructs it and, where `location` is true, the stack\n * that leads to it.\n */\nexport function noteElement(element: FieldBase, location: boolean): void {\n let created: Error | undefined;\n if (location) {\n const limit = Error.stackTraceLimit;\n Error.stackTraceLimit = 20;\n created = new Error();\n Error.stackTraceLimit = limit;\n }\n const instance = getCurrentInstance();\n const entry: Entry = {\n id: String(nextId++),\n element: new WeakRef(element),\n created,\n instance: instance ? new WeakRef(instance) : undefined,\n description: {},\n hidden: false,\n described: false,\n };\n entries.set(entry.id, entry);\n byElement.set(element, entry);\n // state a component constructs is listed while the component is mounted: an element is collected only when the\n // garbage collector runs, which can be long after the component was unmounted\n if (instance && getCurrentScope()) {\n onScopeDispose(() => {\n entries.delete(entry.id);\n changed?.();\n });\n }\n}\n\nexport function describe(element: FieldBase, description: StateDescription): void {\n const entry = byElement.get(element);\n if (!entry) return;\n entry.description = { ...entry.description, ...description };\n entry.described = true;\n entry.hidden = false;\n // an element its component handed on before unmounting is listed again, as global state\n if (!entries.has(entry.id)) {\n entry.instance = undefined;\n entries.set(entry.id, entry);\n }\n changed?.();\n}\n\n/**\n * Drops the stack captured for an element a container took: a member is shown inside its container, and its own\n * file is shown again only if the container releases it.\n */\nexport function forgetLocation(element: FieldBase): void {\n const entry = byElement.get(element);\n if (entry) entry.created = undefined;\n}\n\nexport function setHidden(element: FieldBase, hidden: boolean): void {\n const entry = byElement.get(element);\n if (!entry) return;\n entry.hidden = hidden;\n changed?.();\n}\n\nexport function setRegistration(mode: DevtoolsRegistration): void {\n registration = mode;\n changed?.();\n}\n\n/** Lists nothing while `on` is false. */\nexport function setEnabled(on: boolean): void {\n enabled = on;\n changed?.();\n}\n\n/** Reports a committed change. */\nexport function noteChange(): void {\n changed?.();\n}\n\n/** The entry of an element, where it has one. */\nexport function entryOf(element: FieldBase): Entry | undefined {\n return byElement.get(element);\n}\n\nexport function entryById(id: string): Entry | undefined {\n return entries.get(id);\n}\n\n/**\n * The listed elements: alive, not held by a container, not a binding or an item template, not hidden, and in\n * opt-in mode described. Entries whose element was collected are dropped here. Nothing is listed while the devtools\n * are turned off.\n */\nexport function listed(): { entry: Entry; element: FieldBase }[] {\n const out: { entry: Entry; element: FieldBase }[] = [];\n if (!enabled) return out;\n entries.forEach((entry, id) => {\n const element = entry.element.deref();\n if (!element) {\n entries.delete(id);\n return;\n }\n if (entry.hidden || element.parent || context?.isInternal(element)) return;\n if (registration === 'opt-in' && !entry.described) return;\n out.push({ entry, element });\n });\n return out;\n}\n\n/**\n * The path prefix of the library's own files: `…/src/` where the source is served, or `…/dist/` where the build is.\n * Frames from it are skipped when the caller's file is looked up.\n */\nfunction libraryPrefix(): string {\n // the first frame of a stack taken here is this module, served from the library's source or from a chunk of its\n // build, which lives in dist/ beside the entry files\n const own = /(?:https?:\\/\\/[^/\\s]+|file:\\/\\/)?(\\/[^\\s?):]+\\.[cm]?[jt]s)/.exec(new Error().stack ?? '')?.[1] ?? '';\n if (own.includes('/src/plugins/devtools/')) return own.slice(0, own.indexOf('/src/') + 5);\n if (own.includes('/dist/')) return own.slice(0, own.lastIndexOf('/dist/') + 6);\n return own;\n}\n\n/** A frame of a stack: the function, where the stack names one, and the file, line and column. */\nexport interface StackFrame {\n name?: string;\n /** a path relative to the served root: Vite serves a project file at `/src/…` */\n file: string;\n line: number;\n column: number;\n}\n\n// a Chrome frame is ` at name (url:line:column)` or ` at url:line:column`; a Firefox and a Safari frame is\n// `name@url:line:column`\nconst chromeFrame = /^\\s*at (?:(.*?) \\()?(\\S+?):(\\d+):(\\d+)\\)?$/;\nconst firefoxFrame = /^(.*?)@(\\S+?):(\\d+):(\\d+)$/;\nconst framePath = /^(?:[a-z]+:\\/\\/[^/\\s]*)?(\\/[^\\s?]+\\.(?:[cm]?[jt]sx?|vue))(?:\\?\\S*)?$/;\n\n/**\n * The frames of `stack` outside the library and `node_modules`, outermost last. A frame without a URL of a script\n * or a `.vue` file is left out.\n */\nexport function callerFrames(stack: string | undefined, library = libraryPrefix()): StackFrame[] {\n const frames: StackFrame[] = [];\n for (const text of stack?.split('\\n') ?? []) {\n const match = chromeFrame.exec(text) ?? firefoxFrame.exec(text);\n const path = match && framePath.exec(match[2])?.[1];\n if (!path || path.startsWith(library) || path.includes('/node_modules/')) continue;\n frames.push({\n name: match[1] || undefined,\n file: path.replace(/^\\//, ''),\n line: Number(match[3]),\n column: Number(match[4]),\n });\n }\n return frames;\n}\n\n/** The file of the first frame of `stack` outside the library and `node_modules`; undefined where there is none. */\nexport function callerFile(stack: string | undefined, library = libraryPrefix()): string | undefined {\n return callerFrames(stack, library)[0]?.file;\n}\n\n/** The names of the components from the root of the app to `instance`, joined by ` > `. */\nexport function componentPath(instance: ComponentInternalInstance): string {\n const names: string[] = [];\n for (let at: ComponentInternalInstance | null = instance; at; at = at.parent) {\n const type = at.type as { name?: string; __name?: string; __file?: string };\n names.unshift(type.name ?? type.__name ?? type.__file?.split('/').pop() ?? 'Anonymous');\n }\n return names.join(' > ');\n}\n"],"mappings":"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"}