@praxisjs/decorators 1.7.0 → 2.0.1

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.
Files changed (266) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/component/component.d.ts +1 -1
  3. package/dist/component/component.d.ts.map +1 -1
  4. package/dist/component/component.js +8 -15
  5. package/dist/component/component.js.map +1 -1
  6. package/dist/component/lazy.d.ts +1 -1
  7. package/dist/component/lazy.d.ts.map +1 -1
  8. package/dist/component/lazy.js +44 -36
  9. package/dist/component/lazy.js.map +1 -1
  10. package/dist/create-class-decorator.d.ts +27 -5
  11. package/dist/create-class-decorator.d.ts.map +1 -1
  12. package/dist/create-class-decorator.js +53 -18
  13. package/dist/create-class-decorator.js.map +1 -1
  14. package/dist/create-field-decorator.d.ts +42 -3
  15. package/dist/create-field-decorator.d.ts.map +1 -1
  16. package/dist/create-field-decorator.js +63 -27
  17. package/dist/create-field-decorator.js.map +1 -1
  18. package/dist/create-getter-decorator.d.ts +81 -16
  19. package/dist/create-getter-decorator.d.ts.map +1 -1
  20. package/dist/create-getter-decorator.js +127 -15
  21. package/dist/create-getter-decorator.js.map +1 -1
  22. package/dist/create-lifecycle-method-decorator.d.ts +21 -3
  23. package/dist/create-lifecycle-method-decorator.d.ts.map +1 -1
  24. package/dist/create-lifecycle-method-decorator.js +25 -18
  25. package/dist/create-lifecycle-method-decorator.js.map +1 -1
  26. package/dist/create-method-decorator.d.ts +43 -3
  27. package/dist/create-method-decorator.d.ts.map +1 -1
  28. package/dist/create-method-decorator.js +49 -8
  29. package/dist/create-method-decorator.js.map +1 -1
  30. package/dist/events/command.d.ts +2 -1
  31. package/dist/events/command.d.ts.map +1 -1
  32. package/dist/events/command.js +10 -8
  33. package/dist/events/command.js.map +1 -1
  34. package/dist/events/emit.d.ts +2 -2
  35. package/dist/events/emit.d.ts.map +1 -1
  36. package/dist/events/emit.js +18 -24
  37. package/dist/events/emit.js.map +1 -1
  38. package/dist/events/on-command.d.ts +2 -1
  39. package/dist/events/on-command.d.ts.map +1 -1
  40. package/dist/events/on-command.js +12 -14
  41. package/dist/events/on-command.js.map +1 -1
  42. package/dist/field.d.ts +51 -0
  43. package/dist/field.d.ts.map +1 -0
  44. package/dist/field.js +82 -0
  45. package/dist/field.js.map +1 -0
  46. package/dist/functions/bind.d.ts +2 -1
  47. package/dist/functions/bind.d.ts.map +1 -1
  48. package/dist/functions/bind.js +4 -4
  49. package/dist/functions/bind.js.map +1 -1
  50. package/dist/functions/debounce.d.ts +2 -2
  51. package/dist/functions/debounce.d.ts.map +1 -1
  52. package/dist/functions/debounce.js +25 -23
  53. package/dist/functions/debounce.js.map +1 -1
  54. package/dist/functions/log.d.ts +2 -1
  55. package/dist/functions/log.d.ts.map +1 -1
  56. package/dist/functions/log.js +38 -40
  57. package/dist/functions/log.js.map +1 -1
  58. package/dist/functions/memo.d.ts +2 -1
  59. package/dist/functions/memo.d.ts.map +1 -1
  60. package/dist/functions/memo.js +41 -40
  61. package/dist/functions/memo.js.map +1 -1
  62. package/dist/functions/once.d.ts +2 -1
  63. package/dist/functions/once.d.ts.map +1 -1
  64. package/dist/functions/once.js +10 -14
  65. package/dist/functions/once.js.map +1 -1
  66. package/dist/functions/retry.d.ts +2 -1
  67. package/dist/functions/retry.d.ts.map +1 -1
  68. package/dist/functions/retry.js +21 -23
  69. package/dist/functions/retry.js.map +1 -1
  70. package/dist/functions/throttle.d.ts +2 -1
  71. package/dist/functions/throttle.d.ts.map +1 -1
  72. package/dist/functions/throttle.js +12 -14
  73. package/dist/functions/throttle.js.map +1 -1
  74. package/dist/functions/until.d.ts +2 -1
  75. package/dist/functions/until.d.ts.map +1 -1
  76. package/dist/functions/until.js +13 -14
  77. package/dist/functions/until.js.map +1 -1
  78. package/dist/functions/watch.d.ts +1 -1
  79. package/dist/functions/watch.d.ts.map +1 -1
  80. package/dist/functions/watch.js +36 -34
  81. package/dist/functions/watch.js.map +1 -1
  82. package/dist/functions/when.d.ts +1 -1
  83. package/dist/functions/when.d.ts.map +1 -1
  84. package/dist/functions/when.js +19 -21
  85. package/dist/functions/when.js.map +1 -1
  86. package/dist/index.d.ts +5 -5
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +2 -2
  89. package/dist/index.js.map +1 -1
  90. package/dist/lifecycle.d.ts +24 -0
  91. package/dist/lifecycle.d.ts.map +1 -0
  92. package/dist/lifecycle.js +55 -0
  93. package/dist/lifecycle.js.map +1 -0
  94. package/dist/properties/compose.d.ts +3 -2
  95. package/dist/properties/compose.d.ts.map +1 -1
  96. package/dist/properties/compose.js +33 -19
  97. package/dist/properties/compose.js.map +1 -1
  98. package/dist/properties/computed.d.ts +12 -10
  99. package/dist/properties/computed.d.ts.map +1 -1
  100. package/dist/properties/computed.js +26 -21
  101. package/dist/properties/computed.js.map +1 -1
  102. package/dist/properties/deep-state.d.ts +2 -1
  103. package/dist/properties/deep-state.d.ts.map +1 -1
  104. package/dist/properties/deep-state.js +66 -60
  105. package/dist/properties/deep-state.js.map +1 -1
  106. package/dist/properties/function-prop.d.ts +2 -1
  107. package/dist/properties/function-prop.d.ts.map +1 -1
  108. package/dist/properties/function-prop.js +20 -22
  109. package/dist/properties/function-prop.js.map +1 -1
  110. package/dist/properties/history.d.ts +2 -2
  111. package/dist/properties/history.d.ts.map +1 -1
  112. package/dist/properties/history.js +34 -33
  113. package/dist/properties/history.js.map +1 -1
  114. package/dist/properties/index.d.ts +1 -0
  115. package/dist/properties/index.d.ts.map +1 -1
  116. package/dist/properties/index.js +1 -0
  117. package/dist/properties/index.js.map +1 -1
  118. package/dist/properties/persisted.d.ts +2 -1
  119. package/dist/properties/persisted.d.ts.map +1 -1
  120. package/dist/properties/persisted.js +24 -18
  121. package/dist/properties/persisted.js.map +1 -1
  122. package/dist/properties/prop.d.ts +2 -1
  123. package/dist/properties/prop.d.ts.map +1 -1
  124. package/dist/properties/prop.js +26 -22
  125. package/dist/properties/prop.js.map +1 -1
  126. package/dist/properties/ref.d.ts +2 -1
  127. package/dist/properties/ref.d.ts.map +1 -1
  128. package/dist/properties/ref.js +11 -8
  129. package/dist/properties/ref.js.map +1 -1
  130. package/dist/properties/resource.d.ts.map +1 -1
  131. package/dist/properties/resource.js +21 -16
  132. package/dist/properties/resource.js.map +1 -1
  133. package/dist/properties/selector.d.ts +12 -0
  134. package/dist/properties/selector.d.ts.map +1 -0
  135. package/dist/properties/selector.js +25 -0
  136. package/dist/properties/selector.js.map +1 -0
  137. package/dist/properties/slot.d.ts +2 -1
  138. package/dist/properties/slot.d.ts.map +1 -1
  139. package/dist/properties/slot.js +22 -20
  140. package/dist/properties/slot.js.map +1 -1
  141. package/dist/properties/state.d.ts.map +1 -1
  142. package/dist/properties/state.js +27 -16
  143. package/dist/properties/state.js.map +1 -1
  144. package/dist/properties/synced.d.ts +2 -1
  145. package/dist/properties/synced.d.ts.map +1 -1
  146. package/dist/properties/synced.js +27 -19
  147. package/dist/properties/synced.js.map +1 -1
  148. package/dist/shared-method.d.ts +14 -0
  149. package/dist/shared-method.d.ts.map +1 -0
  150. package/dist/shared-method.js +87 -0
  151. package/dist/shared-method.js.map +1 -0
  152. package/package.json +14 -5
  153. package/src/component/component.ts +8 -27
  154. package/src/component/lazy.ts +51 -41
  155. package/src/create-class-decorator.ts +90 -31
  156. package/src/create-field-decorator.ts +120 -43
  157. package/src/create-getter-decorator.ts +263 -66
  158. package/src/create-lifecycle-method-decorator.ts +50 -28
  159. package/src/create-method-decorator.ts +119 -13
  160. package/src/events/command.ts +11 -9
  161. package/src/events/emit.ts +16 -22
  162. package/src/events/on-command.ts +17 -18
  163. package/src/field.ts +116 -0
  164. package/src/functions/bind.ts +4 -4
  165. package/src/functions/debounce.ts +25 -23
  166. package/src/functions/log.ts +44 -46
  167. package/src/functions/memo.ts +39 -37
  168. package/src/functions/once.ts +10 -13
  169. package/src/functions/retry.ts +19 -21
  170. package/src/functions/throttle.ts +12 -13
  171. package/src/functions/until.ts +14 -14
  172. package/src/functions/watch.ts +37 -36
  173. package/src/functions/when.ts +18 -20
  174. package/src/index.ts +12 -5
  175. package/src/lifecycle.ts +74 -0
  176. package/src/properties/compose.ts +33 -20
  177. package/src/properties/computed.ts +35 -45
  178. package/src/properties/deep-state.ts +66 -64
  179. package/src/properties/function-prop.ts +25 -27
  180. package/src/properties/history.ts +34 -35
  181. package/src/properties/index.ts +1 -0
  182. package/src/properties/persisted.ts +30 -20
  183. package/src/properties/prop.ts +30 -22
  184. package/src/properties/ref.ts +12 -10
  185. package/src/properties/resource.ts +22 -17
  186. package/src/properties/selector.ts +45 -0
  187. package/src/properties/slot.ts +28 -22
  188. package/src/properties/state.ts +32 -16
  189. package/src/properties/synced.ts +31 -19
  190. package/src/shared-method.ts +101 -0
  191. package/dist/__tests__/component.test.d.ts +0 -2
  192. package/dist/__tests__/component.test.d.ts.map +0 -1
  193. package/dist/__tests__/component.test.js +0 -147
  194. package/dist/__tests__/component.test.js.map +0 -1
  195. package/dist/__tests__/compose.test.d.ts +0 -2
  196. package/dist/__tests__/compose.test.d.ts.map +0 -1
  197. package/dist/__tests__/compose.test.js +0 -164
  198. package/dist/__tests__/compose.test.js.map +0 -1
  199. package/dist/__tests__/deep-state.test.d.ts +0 -2
  200. package/dist/__tests__/deep-state.test.d.ts.map +0 -1
  201. package/dist/__tests__/deep-state.test.js +0 -221
  202. package/dist/__tests__/deep-state.test.js.map +0 -1
  203. package/dist/__tests__/events.test.d.ts +0 -2
  204. package/dist/__tests__/events.test.d.ts.map +0 -1
  205. package/dist/__tests__/events.test.js +0 -295
  206. package/dist/__tests__/events.test.js.map +0 -1
  207. package/dist/__tests__/functions.test.d.ts +0 -2
  208. package/dist/__tests__/functions.test.d.ts.map +0 -1
  209. package/dist/__tests__/functions.test.js +0 -618
  210. package/dist/__tests__/functions.test.js.map +0 -1
  211. package/dist/__tests__/lazy.test.d.ts +0 -2
  212. package/dist/__tests__/lazy.test.d.ts.map +0 -1
  213. package/dist/__tests__/lazy.test.js +0 -227
  214. package/dist/__tests__/lazy.test.js.map +0 -1
  215. package/dist/__tests__/memo.test.d.ts +0 -2
  216. package/dist/__tests__/memo.test.d.ts.map +0 -1
  217. package/dist/__tests__/memo.test.js +0 -249
  218. package/dist/__tests__/memo.test.js.map +0 -1
  219. package/dist/__tests__/properties-browser.test.d.ts +0 -2
  220. package/dist/__tests__/properties-browser.test.d.ts.map +0 -1
  221. package/dist/__tests__/properties-browser.test.js +0 -227
  222. package/dist/__tests__/properties-browser.test.js.map +0 -1
  223. package/dist/__tests__/properties.test.d.ts +0 -2
  224. package/dist/__tests__/properties.test.d.ts.map +0 -1
  225. package/dist/__tests__/properties.test.js +0 -1253
  226. package/dist/__tests__/properties.test.js.map +0 -1
  227. package/dist/__tests__/ref.test.d.ts +0 -2
  228. package/dist/__tests__/ref.test.d.ts.map +0 -1
  229. package/dist/__tests__/ref.test.js +0 -106
  230. package/dist/__tests__/ref.test.js.map +0 -1
  231. package/dist/__tests__/resource.test.d.ts +0 -2
  232. package/dist/__tests__/resource.test.d.ts.map +0 -1
  233. package/dist/__tests__/resource.test.js +0 -217
  234. package/dist/__tests__/resource.test.js.map +0 -1
  235. package/dist/__tests__/slot.test.d.ts +0 -2
  236. package/dist/__tests__/slot.test.d.ts.map +0 -1
  237. package/dist/__tests__/slot.test.js +0 -147
  238. package/dist/__tests__/slot.test.js.map +0 -1
  239. package/dist/__tests__/synced.test.d.ts +0 -2
  240. package/dist/__tests__/synced.test.d.ts.map +0 -1
  241. package/dist/__tests__/synced.test.js +0 -161
  242. package/dist/__tests__/synced.test.js.map +0 -1
  243. package/dist/__tests__/until.test.d.ts +0 -2
  244. package/dist/__tests__/until.test.d.ts.map +0 -1
  245. package/dist/__tests__/until.test.js +0 -88
  246. package/dist/__tests__/until.test.js.map +0 -1
  247. package/dist/create-accessor-decorator.d.ts +0 -14
  248. package/dist/create-accessor-decorator.d.ts.map +0 -1
  249. package/dist/create-accessor-decorator.js +0 -27
  250. package/dist/create-accessor-decorator.js.map +0 -1
  251. package/src/__tests__/component.test.ts +0 -167
  252. package/src/__tests__/compose.test.ts +0 -202
  253. package/src/__tests__/deep-state.test.ts +0 -265
  254. package/src/__tests__/events.test.ts +0 -366
  255. package/src/__tests__/functions.test.ts +0 -803
  256. package/src/__tests__/lazy.test.ts +0 -296
  257. package/src/__tests__/memo.test.ts +0 -293
  258. package/src/__tests__/properties-browser.test.ts +0 -288
  259. package/src/__tests__/properties.test.ts +0 -1556
  260. package/src/__tests__/ref.test.ts +0 -131
  261. package/src/__tests__/resource.test.ts +0 -246
  262. package/src/__tests__/slot.test.ts +0 -179
  263. package/src/__tests__/synced.test.ts +0 -193
  264. package/src/__tests__/until.test.ts +0 -113
  265. package/src/create-accessor-decorator.ts +0 -45
  266. package/tsconfig.json +0 -9
package/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # @praxisjs/decorators
2
2
 
3
+ ## 2.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 05518dc: Depend on other `@praxisjs/*` packages through caret ranges (`^2.3.0`) instead of exact versions (`2.3.0`), and accept any `@praxisjs/css` 0.3.x as the peer of `@praxisjs/vite-plugin`. Exact versions made npm install a second copy of a package as soon as two releases disagreed, and turned upgrades into peer conflicts that npm could not resolve (`ERESOLVE`, or a crash in its peer resolution).
8
+ - Updated dependencies [05518dc]
9
+ - @praxisjs/core@2.3.1
10
+
11
+ ## 2.0.0
12
+
13
+ ### Major Changes
14
+
15
+ - 75115a9: Remove the `accessor`-based APIs: `createAccessorDecorator` (with `AccessorBehavior` and `AccessorBinding`) and the `@Computed({ get, set })` form declared on an `accessor` field. Use `createFieldDecorator` with `setup` on a plain field, and a `@Computed()` getter with a `set` accessor next to it. See the migration notes in "Creating Decorators".
16
+
17
+ Add a shared `setup` form to `createFieldDecorator`, `createMethodDecorator`, `createGetterDecorator` and `createWritableGetterDecorator`: created once per decorated member, shared by every instance, with per-instance state in symbol slots and optional `init`/`onMount`/`onUnmount`. `ClassBehavior` can define `onMount(instance)`, `onUnmount(instance)` and `render(instance, originalRender)` itself, and `create` is optional. `createGetterObserverDecorator` takes `register` (per mount) and runs a cleanup returned by `observe` on unmount. Every builder takes a `label`, checks the member kind with a clear `TypeError`, and has typed `Host`/`Value` parameters.
18
+
19
+ The per-instance forms are faster: `createMethodDecorator({ wrap })` and `createWritableGetterDecorator({ bind })` call through one replacement on the class instead of defining a property on every instance (detached `wrap` methods are now bound and stack under built-in method decorators), and `@Computed()` installs its getter on the class. Fixes `@Computed()` with a `set` accessor declared next to the getter, which threw on assignment.
20
+
21
+ ### Minor Changes
22
+
23
+ - 75115a9: Decorated fields are defined by their innermost decorator. With `@praxisjs/vite-plugin`, `@State()`, `@Prop()`, every built-in field decorator and `createFieldDecorator` bindings install their property directly with the field's initial value instead of replacing a plain value, which kept every instance in V8's slow dictionary mode. New `addClaimableInitializer(context, init)` export for field decorators written against the TC39 API.
24
+ - 75115a9: Field decorators throw a `TypeError` when the class is defined if they decorate an `accessor`, naming the member to fix. Covers `@State()`, `@Prop()`, every built-in field decorator and `createFieldDecorator` bindings. New `assertFieldContext(context, label?)` export for field decorators written against the TC39 API directly.
25
+ - 75115a9: Cheaper decorators per instance and per call. Method decorators (`@Bind`, `@Once`, `@Throttle`, `@Debounce`, `@Retry`, `@Log`, `@Memo`, `@Emit`, `@Until`) replace the method once on the class and bind it lazily on first read, field decorators share one accessor pair per field with per-instance state in symbol slots, lifecycle hooks chain without bound functions, and slots, `@Persisted` and `@Synced` no longer read `WeakMap`s. Fixes `@Until` on `@State` fields, a leaked registration when `onMount()` runs twice, stacked method decorators dropping all but one, and method decorators on private methods doing nothing.
26
+ - 75115a9: Rendering and reactivity performance overhaul. `@praxisjs/core` has a new push-pull reactive graph (linked dependencies reused across runs, version-checked computeds, glitch-free effects) and keeps component internals on the instance. `@praxisjs/decorators` shares one accessor pair per `@State`/`@Prop` field, creates `@Computed` lazily, and `@Component` no longer wraps the class. `@praxisjs/runtime` adds the compiled-template helpers, a shared event dispatcher, leaner scopes and reactive children, skipped no-op prop writes, cheaper component mounting and a detached fill for large `For` renders, and fixes a static `<select>` value being lost. `@praxisjs/vite-plugin` compiles JSX trees of host elements into templates cloned per render (`templates` option, on by default).
27
+ - 75115a9: Add a keyed selection primitive. `selector(source, equals?)` in `@praxisjs/core/internal` and the `@Selector(field, { equals })` field decorator expose `isSelected(key)`, whose subscribers are grouped by key: a change to the source re-runs only the effects that read the previous or the next key, instead of every row comparing against it. Key buckets and the source subscription are released when their effects are disposed.
28
+
29
+ ### Patch Changes
30
+
31
+ - 75115a9: Edge-case fixes in the new fast paths. `@praxisjs/vite-plugin` keeps a claimed field's initializer in the field's own scope instead of moving it into the constructor, where a constructor parameter or local of the same name shadowed what it read (and `new.target` fields are claimed too). `selector()` from `@praxisjs/core` compares against the current source value when read outside an effect, also inside a batch or an event handler before its subscribers are notified. `@praxisjs/runtime` keeps updating a hydrated element through a reactive child that fills it alone, rebuilds compiled templates when `render()` runs with another global document (a new SSG window), and always writes `open`, `selectedIndex`, media and scroll props from reactive bindings so a re-run restores what the user changed. Compiled templates keep the leading whitespace of JSX text (`{v} / {m}` lost its first space) and keep tabs inside a line, as the JSX transform does. Methods of `@Bind`, `@Emit` and the other built-in method decorators can be spied on with `vi.spyOn(instance, name)` before their first read again. `@praxisjs/router`'s `Link` removes its `class` attribute when it stops being active instead of leaving `class=""`.
32
+ - 75115a9: Published packages no longer contain their tests: package builds compile `src` without `src/**/__tests__` (through a `tsconfig.build.json`), and each package's `files` leaves test sources and stale compiled tests out of the tarball. `pnpm typecheck` still type-checks the tests.
33
+ - 75115a9: Smaller production bundles. The framework and feature packages are marked `"sideEffects": false`, so bundlers leave out the modules an app does not use (`For`/`Index` and `selector()` were kept in every bundle by their shape keepers). `@praxisjs/core`'s graph gates its observer instrumentation on a boolean that minifiers fold away when no observer is ever installed. `@praxisjs/runtime` passes `Index`'s positional update to the list view, so `For`-only apps leave it out, and builds its event prop table from camel-case names. `@praxisjs/devtools` is built one file per module and its decorators check `process.env.NODE_ENV` inline, so `@Trace`/`@Debug` in production code no longer bundle the registry and the panel. `@praxisjs/vite-plugin` serves TypeScript's decorator helpers and the claimed fields' helper from one virtual module (`virtual:praxisjs/decorators`) instead of writing them into every decorated file, and replaces the identical copies `tsc` wrote into ES module libraries.
34
+ - Updated dependencies [75115a9]
35
+ - Updated dependencies [75115a9]
36
+ - Updated dependencies [75115a9]
37
+ - Updated dependencies [75115a9]
38
+ - Updated dependencies [75115a9]
39
+ - Updated dependencies [75115a9]
40
+ - Updated dependencies [75115a9]
41
+ - @praxisjs/core@2.3.0
42
+ - @praxisjs/shared@0.3.2
43
+
3
44
  ## 1.7.0
4
45
 
5
46
  ### Minor Changes
@@ -1,3 +1,3 @@
1
1
  import type { ComponentConstructor, ComponentInstance } from "@praxisjs/shared/internal";
2
- export declare function Component(): <T extends new (...args: any[]) => ComponentInstance>(constructor: T, context: ClassDecoratorContext) => T & ComponentConstructor;
2
+ export declare function Component(): <T extends new (...args: any[]) => ComponentInstance>(constructor: T, _context: ClassDecoratorContext) => T & ComponentConstructor;
3
3
  //# sourceMappingURL=component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/component/component.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,2BAA2B,CAAC;AAuBnC,wBAAgB,SAAS,KAEN,CAAC,SAAS,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,iBAAiB,EAClE,aAAa,CAAC,EACd,SAAS,qBAAqB,KAC7B,CAAC,GAAG,oBAAoB,CAM5B"}
1
+ {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/component/component.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,2BAA2B,CAAC;AAKnC,wBAAgB,SAAS,KAEN,CAAC,SAAS,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,iBAAiB,EAClE,aAAa,CAAC,EACd,UAAU,qBAAqB,KAC9B,CAAC,GAAG,oBAAoB,CAM5B"}
@@ -1,21 +1,14 @@
1
1
  import { StatelessComponent } from "@praxisjs/core";
2
- import { ClassBehavior, createClassDecorator, } from "../create-class-decorator";
3
- class ComponentBehavior extends ClassBehavior {
4
- create(_instance) {
5
- return {};
6
- }
7
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
- initialize(Enhanced, original) {
9
- const isStateless = original.prototype instanceof StatelessComponent;
10
- Object.defineProperty(Enhanced, "__isComponent", { value: true, configurable: true });
11
- Object.defineProperty(Enhanced, "__isStateless", { value: isStateless, configurable: true });
12
- }
13
- }
14
- const behavior = new ComponentBehavior();
2
+ // @Component only marks the class for the runtime. It adds no behavior, so it marks the class itself
3
+ // instead of wrapping it in an enhanced subclass: every instance would otherwise pay for the
4
+ // wrapper's per-instance object and per-render closure.
15
5
  export function Component() {
16
6
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
- return function (constructor, context) {
18
- return createClassDecorator(behavior)(constructor, context);
7
+ return function (constructor, _context) {
8
+ const isStateless = constructor.prototype instanceof StatelessComponent;
9
+ Object.defineProperty(constructor, "__isComponent", { value: true, configurable: true });
10
+ Object.defineProperty(constructor, "__isStateless", { value: isStateless, configurable: true });
11
+ return constructor;
19
12
  };
20
13
  }
21
14
  //# sourceMappingURL=component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"component.js","sourceRoot":"","sources":["../../src/component/component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAOpD,OAAO,EACL,aAAa,EACb,oBAAoB,GAErB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,iBAAkB,SAAQ,aAAa;IAC3C,MAAM,CAAC,SAAwB;QAC7B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,8DAA8D;IAC9D,UAAU,CAAC,QAAyC,EAAE,QAAyC;QAC7F,MAAM,WAAW,GAAI,QAAQ,CAAC,SAAoB,YAAY,kBAAkB,CAAC;QACjF,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACtF,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/F,CAAC;CACF;AAED,MAAM,QAAQ,GAAG,IAAI,iBAAiB,EAAE,CAAC;AAEzC,MAAM,UAAU,SAAS;IACvB,8DAA8D;IAC9D,OAAO,UACL,WAAc,EACd,OAA8B;QAE9B,OAAO,oBAAoB,CAAC,QAAQ,CAAC,CACnC,WAAiG,EACjG,OAAO,CAC+B,CAAC;IAC3C,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"component.js","sourceRoot":"","sources":["../../src/component/component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAMpD,qGAAqG;AACrG,6FAA6F;AAC7F,wDAAwD;AACxD,MAAM,UAAU,SAAS;IACvB,8DAA8D;IAC9D,OAAO,UACL,WAAc,EACd,QAA+B;QAE/B,MAAM,WAAW,GAAI,WAAW,CAAC,SAAoB,YAAY,kBAAkB,CAAC;QACpF,MAAM,CAAC,cAAc,CAAC,WAAW,EAAE,eAAe,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACzF,MAAM,CAAC,cAAc,CAAC,WAAW,EAAE,eAAe,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAChG,OAAO,WAAuC,CAAC;IACjD,CAAC,CAAC;AACJ,CAAC"}
@@ -13,5 +13,5 @@ export interface LazyOptions {
13
13
  /** Extra margin around the root before triggering (e.g. `"200px"`). Defaults to `"100px"`. */
14
14
  rootMargin?: string;
15
15
  }
16
- export declare function Lazy(placeholderOrOptions?: number | LazyOptions): <T extends new (...args: any[]) => RootComponent<Record<string, any>>>(constructor: T, _context: ClassDecoratorContext) => T;
16
+ export declare function Lazy(placeholderOrOptions?: number | LazyOptions): <T extends new (...args: any[]) => RootComponent<Record<string, any>>>(constructor: T, context: ClassDecoratorContext) => T;
17
17
  //# sourceMappingURL=lazy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../../src/component/lazy.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EAEnB,MAAM,yBAAyB,CAAC;AAIjC,MAAM,WAAW,WAAW;IAC1B,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,IAAI,CAAC,EAAE;QAAE,OAAO,EAAE,WAAW,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9C,8FAA8F;IAC9F,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAuDD,wBAAgB,IAAI,CAAC,oBAAoB,GAAE,MAAM,GAAG,WAAiB,mBAxC7D,GAAJ,0GA8CH"}
1
+ {"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../../src/component/lazy.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,aAAa,EAGnB,MAAM,yBAAyB,CAAC;AAIjC,MAAM,WAAW,WAAW;IAC1B,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,IAAI,CAAC,EAAE;QAAE,OAAO,EAAE,WAAW,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9C,8FAA8F;IAC9F,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA+DD,wBAAgB,IAAI,CAAC,oBAAoB,GAAE,MAAM,GAAG,WAAiB,+HAMpE"}
@@ -1,5 +1,47 @@
1
- import { getComponentAnchor, signal, } from "@praxisjs/core/internal";
1
+ import { getComponentAnchor, readSignal, SignalNode, writeSignal, } from "@praxisjs/core/internal";
2
2
  import { ClassBehavior, createClassDecorator } from "../create-class-decorator";
3
+ // One object per instance whose methods live on the prototype, instead of three closures.
4
+ class LazyEnhancement {
5
+ instance;
6
+ options;
7
+ visible = new SignalNode(false);
8
+ observer = undefined;
9
+ constructor(instance, options) {
10
+ this.instance = instance;
11
+ this.options = options;
12
+ }
13
+ onMount() {
14
+ const el = getComponentAnchor(this.instance)?.parentElement ?? null;
15
+ if (!el)
16
+ return;
17
+ if (!("IntersectionObserver" in window)) {
18
+ writeSignal(this.visible, true);
19
+ return;
20
+ }
21
+ const { placeholder = 200, root, rootMargin = "100px" } = this.options;
22
+ if (!this.visible.value)
23
+ el.style.minHeight = `${String(placeholder)}px`;
24
+ const rootEl = root === undefined || root === null ? null : root.current ?? null;
25
+ this.observer = new IntersectionObserver((entries) => {
26
+ if (entries[0]?.isIntersecting) {
27
+ writeSignal(this.visible, true);
28
+ el.style.minHeight = "";
29
+ this.observer?.disconnect();
30
+ }
31
+ }, { root: rootEl, rootMargin });
32
+ this.observer.observe(el);
33
+ }
34
+ onUnmount() {
35
+ this.observer?.disconnect();
36
+ }
37
+ render(originalRender) {
38
+ return (() => {
39
+ if (!readSignal(this.visible))
40
+ return null;
41
+ return originalRender();
42
+ });
43
+ }
44
+ }
3
45
  class LazyBehavior extends ClassBehavior {
4
46
  options;
5
47
  constructor(options) {
@@ -7,41 +49,7 @@ class LazyBehavior extends ClassBehavior {
7
49
  this.options = options;
8
50
  }
9
51
  create(instance) {
10
- const { placeholder = 200, root, rootMargin = "100px" } = this.options;
11
- const visible = signal(false);
12
- let observer;
13
- return {
14
- onMount() {
15
- const el = getComponentAnchor(instance)?.parentElement ?? null;
16
- if (!el)
17
- return;
18
- if (!("IntersectionObserver" in window)) {
19
- visible.set(true);
20
- return;
21
- }
22
- if (!visible())
23
- el.style.minHeight = `${String(placeholder)}px`;
24
- const rootEl = root === undefined || root === null ? null : root.current ?? null;
25
- observer = new IntersectionObserver((entries) => {
26
- if (entries[0]?.isIntersecting) {
27
- visible.set(true);
28
- el.style.minHeight = "";
29
- observer?.disconnect();
30
- }
31
- }, { root: rootEl, rootMargin });
32
- observer.observe(el);
33
- },
34
- onUnmount() {
35
- observer?.disconnect();
36
- },
37
- render(originalRender) {
38
- return (() => {
39
- if (!visible())
40
- return null;
41
- return originalRender();
42
- });
43
- },
44
- };
52
+ return new LazyEnhancement(instance, this.options);
45
53
  }
46
54
  }
47
55
  export function Lazy(placeholderOrOptions = 200) {
@@ -1 +1 @@
1
- {"version":3,"file":"lazy.js","sourceRoot":"","sources":["../../src/component/lazy.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAElB,MAAM,GACP,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAyB,MAAM,2BAA2B,CAAC;AAevG,MAAM,YAAa,SAAQ,aAAa;IACT;IAA7B,YAA6B,OAAoB;QAC/C,KAAK,EAAE,CAAC;QADmB,YAAO,GAAP,OAAO,CAAa;IAEjD,CAAC;IAED,MAAM,CAAC,QAAuB;QAC5B,MAAM,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QACvE,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,QAA0C,CAAC;QAE/C,OAAO;YACL,OAAO;gBACL,MAAM,EAAE,GAAG,kBAAkB,CAAC,QAAQ,CAAC,EAAE,aAAa,IAAI,IAAI,CAAC;gBAC/D,IAAI,CAAC,EAAE;oBAAE,OAAO;gBAEhB,IAAI,CAAC,CAAC,sBAAsB,IAAI,MAAM,CAAC,EAAE,CAAC;oBACxC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBAClB,OAAO;gBACT,CAAC;gBAED,IAAI,CAAC,OAAO,EAAE;oBAAE,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC;gBAEhE,MAAM,MAAM,GACV,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;gBAEpE,QAAQ,GAAG,IAAI,oBAAoB,CACjC,CAAC,OAAO,EAAE,EAAE;oBACV,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC;wBAC/B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;wBAClB,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC;wBACxB,QAAQ,EAAE,UAAU,EAAE,CAAC;oBACzB,CAAC;gBACH,CAAC,EACD,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAC7B,CAAC;gBAEF,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACvB,CAAC;YAED,SAAS;gBACP,QAAQ,EAAE,UAAU,EAAE,CAAC;YACzB,CAAC;YAED,MAAM,CAAC,cAAc;gBACnB,OAAO,CAAC,GAAG,EAAE;oBACX,IAAI,CAAC,OAAO,EAAE;wBAAE,OAAO,IAAI,CAAC;oBAC5B,OAAO,cAAc,EAAE,CAAC;gBAC1B,CAAC,CAAoB,CAAC;YACxB,CAAC;SACF,CAAC;IACJ,CAAC;CACF;AAED,MAAM,UAAU,IAAI,CAAC,uBAA6C,GAAG;IACnE,MAAM,OAAO,GACX,OAAO,oBAAoB,KAAK,QAAQ;QACtC,CAAC,CAAC,EAAE,WAAW,EAAE,oBAAoB,EAAE;QACvC,CAAC,CAAC,oBAAoB,CAAC;IAC3B,OAAO,oBAAoB,CAAC,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;AACzD,CAAC"}
1
+ {"version":3,"file":"lazy.js","sourceRoot":"","sources":["../../src/component/lazy.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,UAAU,EAEV,UAAU,EACV,WAAW,GACZ,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAyB,MAAM,2BAA2B,CAAC;AAevG,0FAA0F;AAC1F,MAAM,eAAe;IAKA;IACA;IALF,OAAO,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IACzC,QAAQ,GAAqC,SAAS,CAAC;IAE/D,YACmB,QAAuB,EACvB,OAAoB;QADpB,aAAQ,GAAR,QAAQ,CAAe;QACvB,YAAO,GAAP,OAAO,CAAa;IACpC,CAAC;IAEJ,OAAO;QACL,MAAM,EAAE,GAAG,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,aAAa,IAAI,IAAI,CAAC;QACpE,IAAI,CAAC,EAAE;YAAE,OAAO;QAEhB,IAAI,CAAC,CAAC,sBAAsB,IAAI,MAAM,CAAC,EAAE,CAAC;YACxC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAChC,OAAO;QACT,CAAC;QAED,MAAM,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QACvE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK;YAAE,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC;QAEzE,MAAM,MAAM,GACV,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;QAEpE,IAAI,CAAC,QAAQ,GAAG,IAAI,oBAAoB,CACtC,CAAC,OAAO,EAAE,EAAE;YACV,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC;gBAC/B,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;gBAChC,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC;gBACxB,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC;YAC9B,CAAC;QACH,CAAC,EACD,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAC7B,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED,SAAS;QACP,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC;IAC9B,CAAC;IAED,MAAM,CAAC,cAA0C;QAC/C,OAAO,CAAC,GAAG,EAAE;YACX,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC3C,OAAO,cAAc,EAAE,CAAC;QAC1B,CAAC,CAAoB,CAAC;IACxB,CAAC;CACF;AAED,MAAM,YAAa,SAAQ,aAAa;IACT;IAA7B,YAA6B,OAAoB;QAC/C,KAAK,EAAE,CAAC;QADmB,YAAO,GAAP,OAAO,CAAa;IAEjD,CAAC;IAED,MAAM,CAAC,QAAuB;QAC5B,OAAO,IAAI,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACrD,CAAC;CACF;AAED,MAAM,UAAU,IAAI,CAAC,uBAA6C,GAAG;IACnE,MAAM,OAAO,GACX,OAAO,oBAAoB,KAAK,QAAQ;QACtC,CAAC,CAAC,EAAE,WAAW,EAAE,oBAAoB,EAAE;QACvC,CAAC,CAAC,oBAAoB,CAAC;IAC3B,OAAO,oBAAoB,CAAC,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;AACzD,CAAC"}
@@ -1,16 +1,38 @@
1
1
  import type { RootComponent } from "@praxisjs/core/internal";
2
+ type RenderResult = Node | Node[] | null;
2
3
  export interface ClassEnhancement {
3
4
  onMount?(): void;
4
5
  onUnmount?(): void;
5
- render?(originalRender: () => Node | Node[] | null): Node | Node[] | null;
6
+ render?(originalRender: () => RenderResult): RenderResult;
6
7
  }
7
- export declare abstract class ClassBehavior {
8
- abstract create(instance: RootComponent): ClassEnhancement;
8
+ type AnyConstructor = new (...args: any[]) => unknown;
9
+ type AnyComponent = RootComponent<Record<string, any>>;
10
+ /**
11
+ * The behavior a class decorator adds. Every method is optional: hooks that take the instance
12
+ * (`onMount`, `onUnmount`, `render`) live on the behavior itself and allocate nothing per
13
+ * instance; `create` returns a per-instance `ClassEnhancement` when hooks need their own closures.
14
+ */
15
+ export declare abstract class ClassBehavior<Instance extends object = AnyComponent> {
16
+ /** Names the decorator in error messages, e.g. `"@Analytics()"`. */
17
+ label?: string;
18
+ /** Runs once per instance, after its own constructor. */
19
+ create?(instance: Instance): ClassEnhancement;
20
+ /** Runs on every mount of each instance, after the class's own `onMount`. */
21
+ onMount?(instance: Instance): void;
22
+ /** Runs on every unmount of each instance, after the class's own `onUnmount`. */
23
+ onUnmount?(instance: Instance): void;
24
+ /** Wraps every render of each instance; `originalRender` renders the class's own output. */
25
+ render?(instance: Instance, originalRender: () => RenderResult): RenderResult;
9
26
  /**
10
27
  * Called once after the enhanced class is created.
11
28
  * Use this to set static properties on the class constructor itself.
12
29
  */
13
- initialize?(_Enhanced: new (...args: any[]) => unknown, _original: new (...args: any[]) => unknown): void;
30
+ initialize?(_Enhanced: AnyConstructor, _original: AnyConstructor): void;
14
31
  }
15
- export declare function createClassDecorator(behavior: ClassBehavior): <T extends new (...args: any[]) => RootComponent<Record<string, any>>>(constructor: T, _context: ClassDecoratorContext) => T;
32
+ /**
33
+ * Builds a class decorator from a `ClassBehavior`. The class is extended by a subclass that runs
34
+ * the behavior's hooks; a behavior with only `initialize` leaves the class as it is.
35
+ */
36
+ export declare function createClassDecorator<Instance extends object = AnyComponent>(behavior: ClassBehavior<Instance>): <T extends new (...args: any[]) => Instance>(constructor: T, context: ClassDecoratorContext) => T;
37
+ export {};
16
38
  //# sourceMappingURL=create-class-decorator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-class-decorator.d.ts","sourceRoot":"","sources":["../src/create-class-decorator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,IAAI,IAAI,CAAC;IACjB,SAAS,CAAC,IAAI,IAAI,CAAC;IACnB,MAAM,CAAC,CACL,cAAc,EAAE,MAAM,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,GACzC,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;CACzB;AAED,8BAAsB,aAAa;IACjC,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,aAAa,GAAG,gBAAgB;IAE1D;;;OAGG;IAEH,UAAU,CAAC,CAAC,SAAS,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,EAAE,SAAS,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,GAAG,IAAI;CAC1G;AAQD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,aAAa,IAGxD,CAAC,SAAS,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,EACpE,aAAa,CAAC,EAAE,UAAU,qBAAqB,KAAG,CAAC,CAyCtD"}
1
+ {"version":3,"file":"create-class-decorator.d.ts","sourceRoot":"","sources":["../src/create-class-decorator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAI7D,KAAK,YAAY,GAAG,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;AAEzC,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,IAAI,IAAI,CAAC;IACjB,SAAS,CAAC,IAAI,IAAI,CAAC;IACnB,MAAM,CAAC,CAAC,cAAc,EAAE,MAAM,YAAY,GAAG,YAAY,CAAC;CAC3D;AAGD,KAAK,cAAc,GAAG,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC;AAEtD,KAAK,YAAY,GAAG,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;AAEvD;;;;GAIG;AACH,8BAAsB,aAAa,CAAC,QAAQ,SAAS,MAAM,GAAG,YAAY;IACxE,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,yDAAyD;IACzD,MAAM,CAAC,CAAC,QAAQ,EAAE,QAAQ,GAAG,gBAAgB;IAE7C,6EAA6E;IAC7E,OAAO,CAAC,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAElC,iFAAiF;IACjF,SAAS,CAAC,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAEpC,4FAA4F;IAC5F,MAAM,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,GAAG,YAAY;IAE7E;;;OAGG;IACH,UAAU,CAAC,CAAC,SAAS,EAAE,cAAc,EAAE,SAAS,EAAE,cAAc,GAAG,IAAI;CACxE;AAkBD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,SAAS,MAAM,GAAG,YAAY,EAAE,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAAC,IAI1G,CAAC,SAAS,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,QAAQ,EAC1C,aAAa,CAAC,EAAE,SAAS,qBAAqB,KAAG,CAAC,CA6DrD"}
@@ -1,40 +1,75 @@
1
+ import { assertMemberKind } from "./field";
2
+ /**
3
+ * The behavior a class decorator adds. Every method is optional: hooks that take the instance
4
+ * (`onMount`, `onUnmount`, `render`) live on the behavior itself and allocate nothing per
5
+ * instance; `create` returns a per-instance `ClassEnhancement` when hooks need their own closures.
6
+ */
1
7
  export class ClassBehavior {
8
+ /** Names the decorator in error messages, e.g. `"@Analytics()"`. */
9
+ label;
2
10
  }
3
- // Tracks instances whose render is currently being called as `originalRender`
4
- // from within an enhancement. When set, the Enhanced render skips the
5
- // this._enh.render dispatch so stacked decorators (e.g. @Lazy + @Component)
6
- // don't re-enter the outermost enhancement recursively.
7
- const _originalRenderInProgress = new WeakSet();
11
+ // Keyed by symbols so they can't collide with the component's own fields.
12
+ const ENHANCEMENT = Symbol("praxis.classEnhancement");
13
+ // Set on an instance while its render is being called as `originalRender` from within an
14
+ // enhancement. While set, the Enhanced render skips the enhancement's render so stacked decorators
15
+ // (e.g. @Lazy + another render-overriding decorator) don't re-enter the outermost one recursively.
16
+ const IN_ORIGINAL_RENDER = Symbol("praxis.inOriginalRender");
17
+ const NO_ENHANCEMENT = Object.freeze({});
18
+ /**
19
+ * Builds a class decorator from a `ClassBehavior`. The class is extended by a subclass that runs
20
+ * the behavior's hooks; a behavior with only `initialize` leaves the class as it is.
21
+ */
8
22
  export function createClassDecorator(behavior) {
9
- return function (constructor, _context) {
23
+ const label = behavior.label ?? "This class decorator";
24
+ return function (constructor, context) {
25
+ assertMemberKind(context, "class", label);
26
+ const hasCreate = behavior.create !== undefined;
27
+ const sharedRender = behavior.render !== undefined;
28
+ if (!hasCreate && !sharedRender && behavior.onMount === undefined && behavior.onUnmount === undefined) {
29
+ behavior.initialize?.(constructor, constructor);
30
+ return constructor;
31
+ }
32
+ const original = constructor.prototype.render;
10
33
  const Enhanced = class extends constructor {
11
- _enh = behavior.create(this);
34
+ [ENHANCEMENT] = hasCreate
35
+ ? behavior.create(this)
36
+ : NO_ENHANCEMENT;
12
37
  onMount() {
13
38
  super.onMount?.();
14
- this._enh.onMount?.();
39
+ behavior.onMount?.(this);
40
+ this[ENHANCEMENT].onMount?.();
15
41
  }
16
42
  onUnmount() {
17
43
  super.onUnmount?.();
18
- this._enh.onUnmount?.();
44
+ behavior.onUnmount?.(this);
45
+ this[ENHANCEMENT].onUnmount?.();
19
46
  }
20
47
  render(...args) {
21
- const originalRender = () => {
22
- _originalRenderInProgress.add(this);
48
+ const render = original;
49
+ const host = this;
50
+ const enhancement = host[ENHANCEMENT];
51
+ if ((!sharedRender && enhancement.render === undefined) || host[IN_ORIGINAL_RENDER] === true) {
52
+ return render.apply(this, args);
53
+ }
54
+ const renderOriginal = () => {
55
+ host[IN_ORIGINAL_RENDER] = true;
23
56
  try {
24
- return constructor.prototype.render.apply(this, args);
57
+ return render.apply(this, args);
25
58
  }
26
59
  finally {
27
- _originalRenderInProgress.delete(this);
60
+ host[IN_ORIGINAL_RENDER] = false;
28
61
  }
29
62
  };
30
- if (this._enh.render && !_originalRenderInProgress.has(this)) {
31
- return this._enh.render(originalRender);
32
- }
33
- return constructor.prototype.render.apply(this, args);
63
+ const inner = enhancement.render === undefined
64
+ ? renderOriginal
65
+ : () => enhancement.render(renderOriginal);
66
+ if (!sharedRender)
67
+ return inner();
68
+ return behavior.render(this, inner);
34
69
  }
35
70
  };
36
71
  // If the original class has no render, remove the wrapper so instances see `undefined`.
37
- if (typeof constructor.prototype.render !== "function") {
72
+ if (typeof original !== "function") {
38
73
  delete Enhanced.prototype.render;
39
74
  }
40
75
  Object.defineProperty(Enhanced, "name", { value: constructor.name });
@@ -1 +1 @@
1
- {"version":3,"file":"create-class-decorator.js","sourceRoot":"","sources":["../src/create-class-decorator.ts"],"names":[],"mappings":"AAUA,MAAM,OAAgB,aAAa;CASlC;AAED,8EAA8E;AAC9E,sEAAsE;AACtE,4EAA4E;AAC5E,wDAAwD;AACxD,MAAM,yBAAyB,GAAG,IAAI,OAAO,EAAE,CAAC;AAEhD,MAAM,UAAU,oBAAoB,CAAC,QAAuB;IAC1D,OAAO,UAGL,WAAc,EAAE,QAA+B;QAC/C,MAAM,QAAQ,GAAG,KAAM,SAAQ,WAAW;YACvB,IAAI,GAAqB,QAAQ,CAAC,MAAM,CACvD,IAAgC,CACjC,CAAC;YAEF,OAAO;gBACL,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;gBAClB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACxB,CAAC;YAED,SAAS;gBACP,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC;gBACpB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YAC1B,CAAC;YAED,MAAM,CAAC,GAAG,IAAe;gBACvB,MAAM,cAAc,GAAG,GAAG,EAAE;oBAC1B,yBAAyB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBACpC,IAAI,CAAC;wBACH,OAAQ,WAAW,CAAC,SAAmE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;oBACnH,CAAC;4BAAS,CAAC;wBACT,yBAAyB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;oBACzC,CAAC;gBACH,CAAC,CAAC;gBACF,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,yBAAyB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC7D,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;gBAC1C,CAAC;gBACD,OAAQ,WAAW,CAAC,SAAmE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACnH,CAAC;SACF,CAAC;QAEF,wFAAwF;QACxF,IAAI,OAAQ,WAAW,CAAC,SAAkC,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YACjF,OAAQ,QAAQ,CAAC,SAAkC,CAAC,MAAM,CAAC;QAC7D,CAAC;QAED,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;QACrE,QAAQ,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAC7C,OAAO,QAAwB,CAAC;IAClC,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"create-class-decorator.js","sourceRoot":"","sources":["../src/create-class-decorator.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { StatefulComponent } from "@praxisjs/core";
2
+ import { type FieldDecorator } from "./field";
2
3
  export interface FieldBinding {
3
4
  /** Replaces the decorated property. If absent, the original property is left untouched. */
4
5
  descriptor?: PropertyDescriptor;
@@ -7,8 +8,46 @@ export interface FieldBinding {
7
8
  onMount?: () => void;
8
9
  onUnmount?: () => void;
9
10
  }
10
- export interface FieldBehavior<T = object> {
11
- bind(instance: T, name: string, initialValue: unknown): FieldBinding;
11
+ export interface FieldBehavior<T = object, Value = unknown> {
12
+ /** Names the decorator in error messages, e.g. `"@SessionValue()"`. */
13
+ label?: string;
14
+ /** Runs once per instance, while it is built. */
15
+ bind(instance: T, name: string, initialValue: Value): FieldBinding;
12
16
  }
13
- export declare function createFieldDecorator<T = StatefulComponent>(behavior: FieldBehavior<T>): <This extends T, Value = unknown>(_value: undefined, context: ClassFieldDecoratorContext<This, Value>) => void;
17
+ /**
18
+ * What a shared field decorator installs. `get` and `set` become one accessor pair shared by every
19
+ * instance (`this` is the instance), so per-instance state belongs in symbol slots on the instance,
20
+ * created in `init`.
21
+ */
22
+ export interface FieldSetup<This = object, Value = unknown> {
23
+ get?(this: This): Value;
24
+ set?(this: This, value: Value): void;
25
+ /**
26
+ * Runs once per instance, before `get`/`set` are installed, with the field's initial value. A
27
+ * decorator stacked under this one has already installed its own property.
28
+ */
29
+ init?: (instance: This, initialValue: Value) => void;
30
+ onMount?: (instance: This) => void;
31
+ onUnmount?: (instance: This) => void;
32
+ /** Defaults to `true`, like a plain field. */
33
+ enumerable?: boolean;
34
+ }
35
+ export interface SharedFieldBehavior<Host = object, Value = unknown> {
36
+ /** Names the decorator in error messages, e.g. `"@Clamp()"`. */
37
+ label?: string;
38
+ /** Runs once per decorated field, when the class is defined. */
39
+ setup(name: string, context: ClassFieldDecoratorContext<Host, Value>): FieldSetup<Host, Value>;
40
+ }
41
+ /**
42
+ * Builds a field decorator.
43
+ *
44
+ * With `setup`, the recommended form, the decorator's accessors are created once per decorated
45
+ * field and shared by every instance, which keeps its state in symbol slots: building an instance
46
+ * allocates no closures and every instance keeps the same hidden class.
47
+ *
48
+ * With `bind`, a binding (descriptor, hooks, extra properties) is created for each instance, which
49
+ * suits decorators that wrap whatever property a decorator stacked under them installed.
50
+ */
51
+ export declare function createFieldDecorator<Host = object, Value = unknown>(behavior: SharedFieldBehavior<Host, Value>): FieldDecorator<Host, Value>;
52
+ export declare function createFieldDecorator<T = StatefulComponent, Value = unknown>(behavior: FieldBehavior<T, Value>): FieldDecorator<T, Value>;
14
53
  //# sourceMappingURL=create-field-decorator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-field-decorator.d.ts","sourceRoot":"","sources":["../src/create-field-decorator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,MAAM,WAAW,YAAY;IAC3B,2FAA2F;IAC3F,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC,iGAAiG;IACjG,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAChD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,MAAM;IACvC,IAAI,CACF,QAAQ,EAAE,CAAC,EACX,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,OAAO,GACpB,YAAY,CAAC;CACjB;AAED,wBAAgB,oBAAoB,CAAC,CAAC,GAAG,iBAAiB,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,IACnE,IAAI,SAAS,CAAC,EAAE,KAAK,GAAG,OAAO,EAC9C,QAAQ,SAAS,EACjB,SAAS,0BAA0B,CAAC,IAAI,EAAE,KAAK,CAAC,KAC/C,IAAI,CA0CR"}
1
+ {"version":3,"file":"create-field-decorator.d.ts","sourceRoot":"","sources":["../src/create-field-decorator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,EAA8D,KAAK,cAAc,EAAkB,MAAM,SAAS,CAAC;AAG1H,MAAM,WAAW,YAAY;IAC3B,2FAA2F;IAC3F,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC,iGAAiG;IACjG,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAChD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,MAAM,EAAE,KAAK,GAAG,OAAO;IACxD,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,GAAG,YAAY,CAAC;CACpE;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU,CAAC,IAAI,GAAG,MAAM,EAAE,KAAK,GAAG,OAAO;IACxD,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,GAAG,KAAK,CAAC;IACxB,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACrC;;;OAGG;IACH,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,KAAK,IAAI,CAAC;IACrD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,KAAK,IAAI,CAAC;IACrC,8CAA8C;IAC9C,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB,CAAC,IAAI,GAAG,MAAM,EAAE,KAAK,GAAG,OAAO;IACjE,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,0BAA0B,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;CAChG;AA6ED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,GAAG,MAAM,EAAE,KAAK,GAAG,OAAO,EACjE,QAAQ,EAAE,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,GACzC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC/B,wBAAgB,oBAAoB,CAAC,CAAC,GAAG,iBAAiB,EAAE,KAAK,GAAG,OAAO,EACzE,QAAQ,EAAE,aAAa,CAAC,CAAC,EAAE,KAAK,CAAC,GAChC,cAAc,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC"}
@@ -1,37 +1,73 @@
1
- export function createFieldDecorator(behavior) {
1
+ import { addClaimableInitializer, assertFieldContext, describeValue } from "./field";
2
+ import { addLifecycleHooks } from "./lifecycle";
3
+ const DEFAULT_LABEL = "This field decorator";
4
+ function defineValue(instance, name, value) {
5
+ Object.defineProperty(instance, name, { value, writable: true, enumerable: true, configurable: true });
6
+ }
7
+ function bindField(behavior) {
8
+ const label = behavior.label ?? DEFAULT_LABEL;
2
9
  return function (_value, context) {
3
- context.addInitializer(function () {
10
+ assertFieldContext(context, label);
11
+ const name = context.name;
12
+ addClaimableInitializer(context, function (initialValue) {
4
13
  const instance = this;
5
- const name = context.name;
6
- const initialValue = instance[name];
7
- const { descriptor, additional, onMount, onUnmount } = behavior.bind(instance, name, initialValue);
14
+ const binding = behavior.bind(instance, name, initialValue);
15
+ if (typeof binding !== "object" || binding === null) {
16
+ throw new TypeError(`${label}: bind() must return an object (a FieldBinding), got ${describeValue(binding)}.`);
17
+ }
18
+ const { descriptor, additional, onMount, onUnmount } = binding;
8
19
  if (descriptor) {
9
- Reflect.deleteProperty(instance, name);
10
- Object.defineProperty(instance, name, {
11
- enumerable: true,
12
- configurable: true,
13
- ...descriptor,
14
- });
20
+ // The descriptor is fresh from bind(), so defaults are filled in place rather than copied.
21
+ descriptor.enumerable ??= true;
22
+ descriptor.configurable ??= true;
23
+ Object.defineProperty(instance, name, descriptor);
15
24
  }
16
- for (const [key, desc] of Object.entries(additional ?? {})) {
17
- Object.defineProperty(instance, key, {
18
- configurable: true,
19
- ...desc,
20
- });
25
+ else if (!Object.hasOwn(instance, name)) {
26
+ // A binding without a descriptor keeps the plain field, which a claimed field has not got yet.
27
+ defineValue(instance, name, initialValue);
21
28
  }
22
- if (onMount ?? onUnmount) {
23
- const prevMount = instance.onMount?.bind(instance);
24
- const prevUnmount = instance.onUnmount?.bind(instance);
25
- instance.onMount = () => {
26
- prevMount?.();
27
- onMount?.();
28
- };
29
- instance.onUnmount = () => {
30
- prevUnmount?.();
31
- onUnmount?.();
32
- };
29
+ if (additional) {
30
+ for (const key in additional) {
31
+ const desc = additional[key];
32
+ desc.configurable ??= true;
33
+ Object.defineProperty(instance, key, desc);
34
+ }
33
35
  }
36
+ if (onMount ?? onUnmount)
37
+ addLifecycleHooks(instance, onMount, onUnmount);
34
38
  });
35
39
  };
36
40
  }
41
+ function sharedFieldDecorator(behavior) {
42
+ const label = behavior.label ?? DEFAULT_LABEL;
43
+ return function (_value, context) {
44
+ assertFieldContext(context, label);
45
+ const name = context.name;
46
+ const result = behavior.setup(name, context);
47
+ if (typeof result !== "object" || result === null) {
48
+ throw new TypeError(`${label}: setup() must return an object (a FieldSetup), got ${describeValue(result)}.`);
49
+ }
50
+ const field = result;
51
+ const { init, onMount, onUnmount } = field;
52
+ const descriptor = field.get === undefined && field.set === undefined
53
+ ? undefined
54
+ // eslint-disable-next-line @typescript-eslint/unbound-method -- installed as accessors, which call them with the instance as `this`
55
+ : { get: field.get, set: field.set, enumerable: field.enumerable ?? true, configurable: true };
56
+ const hooks = onMount !== undefined || onUnmount !== undefined;
57
+ addClaimableInitializer(context, function (value) {
58
+ const instance = this;
59
+ init?.(instance, value);
60
+ if (descriptor !== undefined)
61
+ Object.defineProperty(instance, name, descriptor);
62
+ else if (!Object.hasOwn(instance, name))
63
+ defineValue(instance, name, value);
64
+ if (hooks) {
65
+ addLifecycleHooks(instance, onMount, onUnmount);
66
+ }
67
+ });
68
+ };
69
+ }
70
+ export function createFieldDecorator(behavior) {
71
+ return "setup" in behavior ? sharedFieldDecorator(behavior) : bindField(behavior);
72
+ }
37
73
  //# sourceMappingURL=create-field-decorator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-field-decorator.js","sourceRoot":"","sources":["../src/create-field-decorator.ts"],"names":[],"mappings":"AAmBA,MAAM,UAAU,oBAAoB,CAAwB,QAA0B;IACpF,OAAO,UACL,MAAiB,EACjB,OAAgD;QAEhD,OAAO,CAAC,cAAc,CAAC;YACrB,MAAM,QAAQ,GAAG,IAA0D,CAAC;YAC5E,MAAM,IAAI,GAAG,OAAO,CAAC,IAAc,CAAC;YACpC,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;YAEpC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,QAAQ,CAAC,IAAI,CAClE,QAAa,EACb,IAAI,EACJ,YAAY,CACb,CAAC;YAEF,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;gBACvC,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,EAAE;oBACpC,UAAU,EAAE,IAAI;oBAChB,YAAY,EAAE,IAAI;oBAClB,GAAG,UAAU;iBACd,CAAC,CAAC;YACL,CAAC;YAED,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,CAAC;gBAC3D,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,GAAG,EAAE;oBACnC,YAAY,EAAE,IAAI;oBAClB,GAAG,IAAI;iBACR,CAAC,CAAC;YACL,CAAC;YAED,IAAI,OAAO,IAAI,SAAS,EAAE,CAAC;gBACzB,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACnD,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACvD,QAAQ,CAAC,OAAO,GAAG,GAAG,EAAE;oBACtB,SAAS,EAAE,EAAE,CAAC;oBACd,OAAO,EAAE,EAAE,CAAC;gBACd,CAAC,CAAC;gBACF,QAAQ,CAAC,SAAS,GAAG,GAAG,EAAE;oBACxB,WAAW,EAAE,EAAE,CAAC;oBAChB,SAAS,EAAE,EAAE,CAAC;gBAChB,CAAC,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"create-field-decorator.js","sourceRoot":"","sources":["../src/create-field-decorator.ts"],"names":[],"mappings":"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"}