ember-source 7.2.0-beta.1 → 7.3.0-alpha.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 (70) hide show
  1. package/build-metadata.json +3 -3
  2. package/dist/dev/packages/@ember/-internals/deprecations/index.js +10 -0
  3. package/dist/dev/packages/@ember/-internals/glimmer/index.js +3 -3
  4. package/dist/dev/packages/@ember/-internals/routing/index.js +1 -1
  5. package/dist/dev/packages/@ember/-internals/runtime/lib/mixins/-proxy.js +1 -1
  6. package/dist/dev/packages/@ember/-internals/runtime/lib/mixins/comparable.js +5 -0
  7. package/dist/dev/packages/@ember/application/index.js +2 -2
  8. package/dist/dev/packages/@ember/application/instance.js +21 -1
  9. package/dist/dev/packages/@ember/component/helper.js +321 -1
  10. package/dist/dev/packages/@ember/component/index.js +1 -1
  11. package/dist/dev/packages/@ember/engine/index.js +2 -2
  12. package/dist/dev/packages/@ember/renderer/index.js +1 -1
  13. package/dist/dev/packages/@ember/routing/-internals.js +1 -1
  14. package/dist/dev/packages/@ember/routing/lib/routing-service.js +0 -1
  15. package/dist/dev/packages/@ember/routing/lib/utils.js +1 -1
  16. package/dist/dev/packages/@ember/routing/route.js +1 -1
  17. package/dist/dev/packages/@ember/routing/router-service.js +0 -1
  18. package/dist/dev/packages/@ember/routing/router.js +1 -1
  19. package/dist/dev/packages/@ember/utils/lib/compare.js +5 -2
  20. package/dist/dev/packages/ember/version.js +1 -1
  21. package/dist/dev/packages/router_js/index.js +2 -2
  22. package/dist/dev/packages/shared-chunks/{curly-Ei5G8jhk.js → curly-DGUCLOud.js} +4 -5
  23. package/dist/dev/packages/shared-chunks/curly-brand-B_F79Dep.js +12 -0
  24. package/dist/dev/packages/shared-chunks/helper-brand-C9_8vvOf.js +12 -0
  25. package/dist/dev/packages/shared-chunks/{index-B3pPx1fL.js → index-CCyXUNBa.js} +616 -1573
  26. package/dist/dev/packages/shared-chunks/outlet-CHFL7tun.js +135 -0
  27. package/dist/dev/packages/shared-chunks/setup-registry-BHdDJATP.js +951 -0
  28. package/dist/dev/packages/shared-chunks/{unrecognized-url-error-BJHjL30Q.js → unrecognized-url-error-B8loxkay.js} +1 -1
  29. package/dist/prod/packages/@ember/-internals/deprecations/index.js +10 -0
  30. package/dist/prod/packages/@ember/-internals/glimmer/index.js +3 -3
  31. package/dist/prod/packages/@ember/-internals/routing/index.js +1 -1
  32. package/dist/prod/packages/@ember/-internals/runtime/lib/mixins/-proxy.js +1 -1
  33. package/dist/prod/packages/@ember/-internals/runtime/lib/mixins/comparable.js +5 -0
  34. package/dist/prod/packages/@ember/application/index.js +2 -2
  35. package/dist/prod/packages/@ember/application/instance.js +17 -2
  36. package/dist/prod/packages/@ember/component/helper.js +305 -1
  37. package/dist/prod/packages/@ember/component/index.js +1 -1
  38. package/dist/prod/packages/@ember/engine/index.js +2 -2
  39. package/dist/prod/packages/@ember/renderer/index.js +1 -1
  40. package/dist/prod/packages/@ember/routing/lib/routing-service.js +0 -1
  41. package/dist/prod/packages/@ember/routing/lib/utils.js +1 -1
  42. package/dist/prod/packages/@ember/routing/route.js +1 -1
  43. package/dist/prod/packages/@ember/routing/router-service.js +0 -1
  44. package/dist/prod/packages/@ember/routing/router.js +1 -1
  45. package/dist/prod/packages/@ember/utils/lib/compare.js +5 -2
  46. package/dist/prod/packages/ember/version.js +1 -1
  47. package/dist/prod/packages/router_js/index.js +2 -2
  48. package/dist/prod/packages/shared-chunks/{curly-IY06zACp.js → curly-a6DP7r87.js} +4 -5
  49. package/dist/prod/packages/shared-chunks/curly-brand-B_F79Dep.js +12 -0
  50. package/dist/prod/packages/shared-chunks/helper-brand-C9_8vvOf.js +12 -0
  51. package/dist/prod/packages/shared-chunks/{index-CslMfEpb.js → index-npr2B-vu.js} +546 -1449
  52. package/dist/prod/packages/shared-chunks/outlet--lIm3q7t.js +132 -0
  53. package/dist/prod/packages/shared-chunks/setup-registry-Dfu8EyLU.js +886 -0
  54. package/dist/prod/packages/shared-chunks/{unrecognized-url-error-EgNrnFu_.js → unrecognized-url-error-jjQ-FqKB.js} +1 -1
  55. package/docs/data.json +279 -214
  56. package/package.json +6 -6
  57. package/types/stable/@ember/-internals/deprecations/index.d.ts +6 -0
  58. package/types/stable/@ember/-internals/glimmer/lib/base-renderer.d.ts +150 -0
  59. package/types/stable/@ember/-internals/glimmer/lib/component-managers/curly-brand.d.ts +10 -0
  60. package/types/stable/@ember/-internals/glimmer/lib/component-managers/curly.d.ts +3 -2
  61. package/types/stable/@ember/-internals/glimmer/lib/helper-brand.d.ts +10 -0
  62. package/types/stable/@ember/-internals/glimmer/lib/helper.d.ts +4 -6
  63. package/types/stable/@ember/-internals/glimmer/lib/renderer.d.ts +7 -154
  64. package/types/stable/@ember/-internals/glimmer/lib/router-resolver.d.ts +17 -0
  65. package/types/stable/@ember/renderer/index.d.ts +2 -2
  66. package/types/stable/index.d.ts +590 -586
  67. package/dist/dev/packages/shared-chunks/helper-DIj85_-f.js +0 -326
  68. package/dist/dev/packages/shared-chunks/setup-registry-9DCmHTFF.js +0 -77
  69. package/dist/prod/packages/shared-chunks/helper-DkXiTBjc.js +0 -310
  70. package/dist/prod/packages/shared-chunks/setup-registry-U-6VaNQG.js +0 -74
@@ -0,0 +1,951 @@
1
+ import { privatize } from '../@ember/-internals/container/index.js';
2
+ import { getOwner } from '../@ember/-internals/owner/index.js';
3
+ import '../@ember/debug/index.js';
4
+ import { I as Input, T as Textarea } from './textarea-C4lYkaHj.js';
5
+ import { LinkTo } from '../@ember/routing/index.js';
6
+ import { i as inTransaction, d as renderMain } from './render-87_sKZ_k.js';
7
+ import { c as clientBuilder } from './api-C0PAtEgQ.js';
8
+ import { r as rehydrationBuilder } from './rehydrate-builder-C6k1XhET.js';
9
+ import { s as serializeBuilder } from './serialize-builder-BlxBjwO-.js';
10
+ import { g as guidFor } from './guid-Cbq2sNV_.js';
11
+ import { getViewId, getViewElement } from '../@ember/-internals/views/lib/system/utils.js';
12
+ import { associateDestroyableChild, isDestroyed, destroy, isDestroying } from '../@glimmer/destroyable/index.js';
13
+ import { a as createConstRef, v as valueForRef, c as createComputeRef, h as createDebugAliasRef, g as childRefFromParts, u as updateRef, U as UNDEFINED_REFERENCE } from './reference-BqOLhKFy.js';
14
+ import { c as createCapturedArgs, b as EMPTY_POSITIONAL, d as curry } from './arguments-CDkbOqTS.js';
15
+ import { d as dict } from './collections-DPkjqeA3.js';
16
+ import { C as CurlyComponentManager, i as initialRenderInstrumentDetails, p as processComponentInitializationAssertions, a as ComponentStateBucket, D as DIRTY_TAG, u as unwrapTemplate, B as BOUNDS } from './curly-DGUCLOud.js';
17
+ import { O as OutletComponent, c as createRootOutlet } from './outlet-CHFL7tun.js';
18
+ import { g as getFactoryFor } from './container-BzzHmCNj.js';
19
+ import { _instrumentStart } from '../@ember/instrumentation/index.js';
20
+ import { c as capabilityFlagsFrom } from './capabilities-CajW4QjE.js';
21
+ import { C as CONSTANT_TAG, c as consumeTag, D as DIRTY_TAG$1, r as createTag } from './cache-DGDPVCpC.js';
22
+ import { assert } from '../@ember/debug/lib/assert.js';
23
+ import { R as ResolverImpl, B as BaseRenderer, e as errorLoopTransaction } from './index-CCyXUNBa.js';
24
+ import { generateControllerFactory } from '../@ember/routing/lib/generate_controller.js';
25
+ import { i as internalHelper } from './internal-helper-CKrni0b_.js';
26
+ import { c as hasInternalComponentManager } from './api-DuLOZMO_.js';
27
+ import { schedule } from '../@ember/runloop/index.js';
28
+ import { t as templateFactory } from './index-DaFzpTIE.js';
29
+
30
+ const RootTemplate = templateFactory(
31
+ /*
32
+ {{component this}}
33
+ */
34
+ {
35
+ "id": null,
36
+ "block": "[[[46,[30,0],null,null,null]],[],[\"component\"]]",
37
+ "moduleName": "packages/@ember/-internals/glimmer/lib/templates/root.hbs",
38
+ "isStrictMode": true
39
+ });
40
+
41
+ class RootComponentManager extends CurlyComponentManager {
42
+ component;
43
+ constructor(component) {
44
+ super();
45
+ this.component = component;
46
+ }
47
+ create(_owner, _state, _args, {
48
+ isInteractive
49
+ }, dynamicScope) {
50
+ let component = this.component;
51
+ let finalizer = _instrumentStart('render.component', initialRenderInstrumentDetails, component);
52
+ dynamicScope.view = component;
53
+ let hasWrappedElement = component.tagName !== '';
54
+
55
+ // We usually do this in the `didCreateElement`, but that hook doesn't fire for tagless components
56
+ if (!hasWrappedElement) {
57
+ if (isInteractive) {
58
+ component.trigger('willRender');
59
+ }
60
+ component._transitionTo('hasElement');
61
+ if (isInteractive) {
62
+ component.trigger('willInsertElement');
63
+ }
64
+ }
65
+ {
66
+ processComponentInitializationAssertions(component, {});
67
+ }
68
+ let bucket = new ComponentStateBucket(component, null, CONSTANT_TAG, finalizer, hasWrappedElement, isInteractive);
69
+ consumeTag(component[DIRTY_TAG]);
70
+ return bucket;
71
+ }
72
+ }
73
+
74
+ // ROOT is the top-level template it has nothing but one yield.
75
+ // it is supposed to have a dummy element
76
+ const ROOT_CAPABILITIES = {
77
+ dynamicLayout: true,
78
+ dynamicTag: true,
79
+ prepareArgs: false,
80
+ createArgs: false,
81
+ attributeHook: true,
82
+ elementHook: true,
83
+ createCaller: true,
84
+ dynamicScope: true,
85
+ updateHook: true,
86
+ createInstance: true,
87
+ wrapped: true,
88
+ willDestroy: false,
89
+ hasSubOwner: false
90
+ };
91
+ class RootComponentDefinition {
92
+ // handle is not used by this custom definition
93
+ handle = -1;
94
+ resolvedName = '-top-level';
95
+ state;
96
+ manager;
97
+ capabilities = capabilityFlagsFrom(ROOT_CAPABILITIES);
98
+ compilable = null;
99
+ constructor(component) {
100
+ this.manager = new RootComponentManager(component);
101
+ let factory = getFactoryFor(component);
102
+ (!(factory !== undefined) && assert('missing factory for component', factory !== undefined));
103
+ this.state = factory;
104
+ }
105
+ }
106
+
107
+ const CAPABILITIES$1 = {
108
+ dynamicLayout: true,
109
+ dynamicTag: false,
110
+ prepareArgs: false,
111
+ createArgs: true,
112
+ attributeHook: false,
113
+ elementHook: false,
114
+ createCaller: true,
115
+ dynamicScope: true,
116
+ updateHook: true,
117
+ createInstance: true,
118
+ wrapped: false,
119
+ willDestroy: false,
120
+ hasSubOwner: true
121
+ };
122
+ class MountManager {
123
+ getDynamicLayout(state) {
124
+ let templateFactory = state.engine.lookup('template:application');
125
+ return unwrapTemplate(templateFactory(state.engine)).asLayout();
126
+ }
127
+ getCapabilities() {
128
+ return CAPABILITIES$1;
129
+ }
130
+ getOwner(state) {
131
+ return state.engine;
132
+ }
133
+ create(owner, {
134
+ name
135
+ }, args, env) {
136
+ // TODO
137
+ // mount is a runtime helper, this shouldn't use dynamic layout
138
+ // we should resolve the engine app template in the helper
139
+ // it also should use the owner that looked up the mount helper.
140
+ (!('buildChildEngineInstance' in owner) && assert('Expected owner to be an EngineInstance', 'buildChildEngineInstance' in owner));
141
+ let engine = owner.buildChildEngineInstance(name);
142
+ engine.boot();
143
+ let applicationFactory = engine.factoryFor(`controller:application`);
144
+ let controllerFactory = applicationFactory || generateControllerFactory(engine, 'application');
145
+ let controller;
146
+ let self;
147
+ let bucket;
148
+ let modelRef;
149
+ if (args.named.has('model')) {
150
+ modelRef = args.named.get('model');
151
+ }
152
+ if (modelRef === undefined) {
153
+ controller = controllerFactory.create();
154
+ self = createConstRef(controller, 'this');
155
+ bucket = {
156
+ engine,
157
+ controller,
158
+ self,
159
+ modelRef
160
+ };
161
+ } else {
162
+ let model = valueForRef(modelRef);
163
+ controller = controllerFactory.create({
164
+ model
165
+ });
166
+ self = createConstRef(controller, 'this');
167
+ bucket = {
168
+ engine,
169
+ controller,
170
+ self,
171
+ modelRef
172
+ };
173
+ }
174
+ if (env.debugRenderTree) {
175
+ associateDestroyableChild(engine, controller);
176
+ }
177
+ return bucket;
178
+ }
179
+ getDebugName({
180
+ name
181
+ }) {
182
+ return name;
183
+ }
184
+ getDebugCustomRenderTree(definition, state, args) {
185
+ return [{
186
+ bucket: state.engine,
187
+ instance: state.engine,
188
+ type: 'engine',
189
+ name: definition.name,
190
+ args
191
+ }, {
192
+ bucket: state.controller,
193
+ instance: state.controller,
194
+ type: 'route-template',
195
+ name: 'application',
196
+ args
197
+ }];
198
+ }
199
+ getSelf({
200
+ self
201
+ }) {
202
+ return self;
203
+ }
204
+ getDestroyable(bucket) {
205
+ return bucket.engine;
206
+ }
207
+ didCreate() {}
208
+ didUpdate() {}
209
+ didRenderLayout() {}
210
+ didUpdateLayout() {}
211
+ update(bucket) {
212
+ let {
213
+ controller,
214
+ modelRef
215
+ } = bucket;
216
+ if (modelRef !== undefined) {
217
+ controller.set('model', valueForRef(modelRef));
218
+ }
219
+ }
220
+ }
221
+ const MOUNT_MANAGER = /*@__PURE__*/new MountManager();
222
+ class MountDefinition {
223
+ // handle is not used by this custom definition
224
+ handle = -1;
225
+ state;
226
+ manager = MOUNT_MANAGER;
227
+ compilable = null;
228
+ capabilities = capabilityFlagsFrom(CAPABILITIES$1);
229
+ constructor(resolvedName) {
230
+ this.resolvedName = resolvedName;
231
+ this.state = {
232
+ name: resolvedName
233
+ };
234
+ }
235
+ }
236
+
237
+ /**
238
+ @module ember
239
+ */
240
+
241
+
242
+ /**
243
+ The `{{mount}}` helper lets you embed a routeless engine in a template.
244
+ Mounting an engine will cause an instance to be booted and its `application`
245
+ template to be rendered.
246
+
247
+ For example, the following template mounts the `ember-chat` engine:
248
+
249
+ ```app/templates/application.gjs
250
+ {{mount "ember-chat"}}
251
+ ```
252
+
253
+ Additionally, you can also pass in a `model` argument that will be
254
+ set as the engines model. This can be an existing object:
255
+
256
+ ```hbs
257
+ <div>
258
+ {{mount 'admin' model=userSettings}}
259
+ </div>
260
+ ```
261
+
262
+ Or an inline `hash`, and you can even pass components:
263
+
264
+ ```gjs
265
+ import SignInButton from '../components/sign-in-button';
266
+ <template>
267
+ <div>
268
+ <h1>Application template!</h1>
269
+ {{mount 'admin' model=(hash
270
+ title='Secret Admin'
271
+ signInButton=SignInButton
272
+ )}}
273
+ </div>
274
+ </template>
275
+ ```
276
+
277
+ `mount` is built-in and does not need to be imported.
278
+
279
+ @method mount
280
+ @param {String} name Name of the engine to mount.
281
+ @param {Object} [model] Object that will be set as
282
+ the model of the engine.
283
+ @for Ember.Templates.helpers
284
+ @public
285
+ */
286
+ const mountHelper = /*@__PURE__*/internalHelper((args, owner) => {
287
+ (!(owner) && assert('{{mount}} must be used within a component that has an owner', owner));
288
+ let nameRef = args.positional[0];
289
+ let captured;
290
+ (!(args.positional.length === 1) && assert('You can only pass a single positional argument to the {{mount}} helper, e.g. {{mount "chat-engine"}}.', args.positional.length === 1));
291
+ if (args.named) {
292
+ let keys = Object.keys(args.named);
293
+ let extra = keys.filter(k => k !== 'model');
294
+ (!(extra.length === 0) && assert('You can only pass a `model` argument to the {{mount}} helper, ' + 'e.g. {{mount "profile-engine" model=this.profile}}. ' + `You passed ${extra.join(',')}.`, extra.length === 0));
295
+ }
296
+ captured = createCapturedArgs(args.named, EMPTY_POSITIONAL);
297
+ let lastName, lastDef;
298
+ return createComputeRef(() => {
299
+ let name = valueForRef(nameRef);
300
+ if (typeof name === 'string') {
301
+ if (lastName === name) {
302
+ return lastDef;
303
+ }
304
+ (!(owner.hasRegistration(`engine:${name}`)) && assert(`You used \`{{mount '${name}'}}\`, but the engine '${name}' can not be found.`, owner.hasRegistration(`engine:${name}`)));
305
+ lastName = name;
306
+ lastDef = curry(0, new MountDefinition(name), owner, captured, true);
307
+ return lastDef;
308
+ } else {
309
+ (!(name === null || name === undefined) && assert(`Invalid engine name '${name}' specified, engine name must be either a string, null or undefined.`, name === null || name === undefined));
310
+ lastDef = null;
311
+ lastName = null;
312
+ return null;
313
+ }
314
+ });
315
+ });
316
+
317
+ const CAPABILITIES = {
318
+ dynamicLayout: false,
319
+ dynamicTag: false,
320
+ prepareArgs: false,
321
+ createArgs: true,
322
+ attributeHook: false,
323
+ elementHook: false,
324
+ createCaller: false,
325
+ dynamicScope: false,
326
+ updateHook: false,
327
+ createInstance: true,
328
+ wrapped: false,
329
+ willDestroy: false,
330
+ hasSubOwner: false
331
+ };
332
+ const CAPABILITIES_MASK = /*@__PURE__*/capabilityFlagsFrom(CAPABILITIES);
333
+ class RouteTemplateManager {
334
+ create(_owner, _definition, args) {
335
+ let self = args.named.get('controller');
336
+ {
337
+ self = createDebugAliasRef('this', self);
338
+ }
339
+ let controller = valueForRef(self);
340
+ return {
341
+ self,
342
+ controller
343
+ };
344
+ }
345
+ getSelf({
346
+ self
347
+ }) {
348
+ return self;
349
+ }
350
+ getDebugName({
351
+ name
352
+ }) {
353
+ return `route-template (${name})`;
354
+ }
355
+ getDebugCustomRenderTree({
356
+ name
357
+ }, state, args) {
358
+ return [{
359
+ bucket: state,
360
+ type: 'route-template',
361
+ name,
362
+ args,
363
+ instance: state.controller
364
+ }];
365
+ }
366
+ getCapabilities() {
367
+ return CAPABILITIES;
368
+ }
369
+ didRenderLayout() {}
370
+ didUpdateLayout() {}
371
+ didCreate() {}
372
+ didUpdate() {}
373
+ getDestroyable() {
374
+ return null;
375
+ }
376
+ }
377
+ const ROUTE_TEMPLATE_MANAGER = /*@__PURE__*/new RouteTemplateManager();
378
+
379
+ /**
380
+ * This "upgrades" a route template into a invocable component. Conceptually
381
+ * it can be 1:1 for each unique `Template`, but it's also cheap to construct,
382
+ * so unless the stability is desirable for other reasons, it's probably not
383
+ * worth caching this.
384
+ */
385
+ class RouteTemplate {
386
+ // handle is not used by this custom definition
387
+ handle = -1;
388
+ resolvedName;
389
+ state;
390
+ manager = ROUTE_TEMPLATE_MANAGER;
391
+ capabilities = CAPABILITIES_MASK;
392
+ compilable;
393
+ constructor(name, template) {
394
+ let unwrapped = unwrapTemplate(template);
395
+ // TODO This actually seems inaccurate – it ultimately came from the
396
+ // outlet's name. Also, setting this overrides `getDebugName()` in that
397
+ // message. Is that desirable?
398
+ this.resolvedName = name;
399
+ this.state = {
400
+ name
401
+ };
402
+ this.compilable = unwrapped.asLayout();
403
+ }
404
+ }
405
+
406
+ // TODO a lot these fields are copied from the adjacent existing components
407
+ // implementation, haven't looked into who cares about `ComponentDefinition`
408
+ // and if it is appropriate here. It seems like this version is intended to
409
+ // be used with `curry` which probably isn't necessary here. It could be the
410
+ // case that we just want to do something more similar to `InternalComponent`
411
+ // (the one we used to implement `Input` and `LinkTo`). For now it follows
412
+ // the same pattern to get things going.
413
+ function makeRouteTemplate(owner, name, template) {
414
+ let routeTemplate = new RouteTemplate(name, template);
415
+ return curry(0, routeTemplate, owner, null, true);
416
+ }
417
+
418
+ /**
419
+ The `{{outlet}}` helper lets you specify where a child route will render in
420
+ your template. An important use of the `{{outlet}}` helper is in your
421
+ application's `application.gjs` file:
422
+
423
+ ```app/templates/application.gjs
424
+ import MyHeader from '../components/my-header';
425
+ import MyFooter from '../components/my-footer';
426
+
427
+ <template>
428
+ <MyHeader />
429
+
430
+ <div class="my-dynamic-content">
431
+ <!-- this content will change based on the current route, which depends on the current URL -->
432
+ {{outlet}}
433
+ </div>
434
+
435
+ <MyFooter />
436
+ </template>
437
+ ```
438
+
439
+ See the [routing guide](https://guides.emberjs.com/release/routing/rendering-a-template/) for more
440
+ information on how your `route` interacts with the `{{outlet}}` helper.
441
+ Note: Your content __will not render__ if there isn't an `{{outlet}}` for it.
442
+
443
+ `outlet` is built-in and does not need to be imported.
444
+
445
+ @method outlet
446
+ @for Ember.Templates.helpers
447
+ @public
448
+ */
449
+ const outletHelper = /*@__PURE__*/internalHelper((_args, owner, scope) => {
450
+ (!(owner) && assert('Expected owner to be present, {{outlet}} requires an owner', owner));
451
+ (!(scope) && assert('Expected dynamic scope to be present. You may have attempted to use the {{outlet}} keyword dynamically. This keyword cannot be used dynamically.', scope));
452
+ let outletRef = createComputeRef(() => {
453
+ let state = valueForRef(scope.get('outletState'));
454
+ return state?.outlets?.main;
455
+ });
456
+ let lastState = null;
457
+ let outlet = null;
458
+ return createComputeRef(() => {
459
+ let outletState = valueForRef(outletRef);
460
+ let state = stateFor(outletRef, outletState);
461
+
462
+ // This code is deliberately using the behavior in glimmer-vm where in
463
+ // <@Component />, the component is considered stabled via `===`, and
464
+ // will continue to re-render in-place as long as the `===` holds, but
465
+ // when it changes to a different object, it teardown the old component
466
+ // (running destructors, etc), and render the component in its place (or
467
+ // nothing if the new value is nullish. Here we are carefully exploiting
468
+ // that fact, and returns the same stable object so long as it is the
469
+ // same route, but return a different one when the route changes. On the
470
+ // other hand, changing the model only intentionally do not teardown the
471
+ // component and instead re-render in-place.
472
+ if (!isStable(state, lastState)) {
473
+ lastState = state;
474
+ if (state !== null) {
475
+ // If we are crossing an engine mount point, this is how the owner
476
+ // gets switched.
477
+ let outletOwner = outletState?.render?.owner ?? owner;
478
+ let named = dict();
479
+
480
+ // Here we either have a raw template that needs to be normalized,
481
+ // or a component that we can render as-is. `RouteTemplate` upgrades
482
+ // the template into a component so we can have a unified code path.
483
+ // We still store the original `template` value, because we rely on
484
+ // its identity for the stability check, and the `RouteTemplate`
485
+ // wrapper doesn't dedup for us.
486
+ let template = state.template;
487
+ let component;
488
+ if (hasInternalComponentManager(template)) {
489
+ component = template;
490
+ } else {
491
+ {
492
+ // We don't appear to have a standard way or a brand to check, but for the
493
+ // purpose of avoiding obvious user errors, this probably gets you close
494
+ // enough.
495
+ let isTemplate = template => {
496
+ if (template === null || typeof template !== 'object') {
497
+ return false;
498
+ } else {
499
+ let t = template;
500
+ return t.result === 'ok' || t.result === 'error';
501
+ }
502
+ };
503
+
504
+ // We made it past the `TemplateFactory` instantiation before
505
+ // getting here, so either we got unlucky where the invalid type
506
+ // happens to be a function that didn't mind taking owner as an
507
+ // argument, or this was directly set by something like test
508
+ // helpers.
509
+ if (!isTemplate(template)) {
510
+ let label;
511
+ try {
512
+ label = `\`${String(template)}\``;
513
+ } catch {
514
+ label = 'an unknown object';
515
+ }
516
+ (assert(`Failed to render the \`${state.name}\` route: expected ` + `a component or Template object, but got ${label}.`));
517
+ }
518
+ }
519
+ component = makeRouteTemplate(outletOwner, state.name, template);
520
+ }
521
+
522
+ // Component is stable for the lifetime of the outlet
523
+ named['Component'] = createConstRef(component, '@Component');
524
+
525
+ // Controller is stable for the lifetime of the outlet
526
+ named['controller'] = createConstRef(state.controller, '@controller');
527
+
528
+ // Create a ref for the model
529
+ let modelRef = childRefFromParts(outletRef, ['render', 'model']);
530
+
531
+ // Store the value of the model
532
+ let model = valueForRef(modelRef);
533
+
534
+ // Create a compute ref which we pass in as the `{{@model}}` reference
535
+ // for the outlet. This ref will update and return the value of the
536
+ // model _until_ the outlet itself changes. Once the outlet changes,
537
+ // dynamic scope also changes, and so the original model ref would not
538
+ // provide the correct updated value. So we stop updating and return
539
+ // the _last_ model value for that outlet.
540
+ named['model'] = createComputeRef(() => {
541
+ if (lastState === state) {
542
+ model = valueForRef(modelRef);
543
+ }
544
+ return model;
545
+ });
546
+ {
547
+ named['model'] = createDebugAliasRef('@model', named['model']);
548
+ }
549
+ let args = createCapturedArgs(named, EMPTY_POSITIONAL);
550
+
551
+ // Package up everything
552
+ outlet = curry(0, new OutletComponent(owner, state), outletOwner, args, true);
553
+ } else {
554
+ outlet = null;
555
+ }
556
+ }
557
+ return outlet;
558
+ });
559
+ });
560
+ function stateFor(ref, outlet) {
561
+ if (outlet === undefined) return null;
562
+ let render = outlet.render;
563
+ if (render === undefined) return null;
564
+ let template = render.template;
565
+ // The type doesn't actually allow for `null`, but if we make it past this
566
+ // point it is really important that we have _something_ to render. We could
567
+ // assert, but that is probably overly strict for very little to gain.
568
+ if (template === undefined || template === null) return null;
569
+ return {
570
+ ref,
571
+ name: render.name,
572
+ template,
573
+ controller: render.controller
574
+ };
575
+ }
576
+ function isStable(state, lastState) {
577
+ if (state === null || lastState === null) {
578
+ return false;
579
+ }
580
+ return state.template === lastState.template && state.controller === lastState.controller;
581
+ }
582
+
583
+ const ROUTER_KEYWORD_HELPERS = {
584
+ '-mount': mountHelper,
585
+ '-outlet': outletHelper
586
+ };
587
+
588
+ /**
589
+ * The resolver used by the classic application `Renderer`. It extends the
590
+ * shared `ResolverImpl` with the keywords that require the router and engine
591
+ * infrastructure (`{{outlet}}` and `{{mount}}`). Keeping these out of the
592
+ * base resolver means renderers that have no router (e.g. `renderComponent`)
593
+ * do not pull the outlet/engine machinery into the build.
594
+ */
595
+ class RouterResolver extends ResolverImpl {
596
+ lookupBuiltInHelper(name) {
597
+ return ROUTER_KEYWORD_HELPERS[name] ?? super.lookupBuiltInHelper(name);
598
+ }
599
+
600
+ // Loose-mode templates resolve the wrapped `{{outlet}}` / `{{mount}}`
601
+ // keywords (`{{component (-outlet)}}`) through `lookupHelper`, not
602
+ // `lookupBuiltInHelper`, so the router keywords have to be added to both
603
+ // lookup paths.
604
+ lookupHelper(name, owner) {
605
+ return ROUTER_KEYWORD_HELPERS[name] ?? super.lookupHelper(name, owner);
606
+ }
607
+ }
608
+
609
+ // We use the `InternalOwner` notion here because we actually need all of its
610
+ // API for using with renderers (normally, it will be `EngineInstance`).
611
+ // We use `getOwner` from our internal home for it rather than the narrower
612
+ // public API for the same reason.
613
+ const TOP_LEVEL_NAME = '-top-level';
614
+ class OutletView {
615
+ static extend(injections) {
616
+ return class extends OutletView {
617
+ static create(options) {
618
+ if (options) {
619
+ return super.create(Object.assign({}, injections, options));
620
+ } else {
621
+ return super.create(injections);
622
+ }
623
+ }
624
+ };
625
+ }
626
+ static reopenClass(injections) {
627
+ Object.assign(this, injections);
628
+ }
629
+ static create(options) {
630
+ let {
631
+ environment: _environment,
632
+ application: namespace,
633
+ template: templateFactory
634
+ } = options;
635
+ let owner = getOwner(options);
636
+ (!(owner) && assert('OutletView is unexpectedly missing an owner', owner));
637
+ let template = templateFactory(owner);
638
+ return new OutletView(_environment, owner, template, namespace);
639
+ }
640
+ ref;
641
+ state;
642
+ constructor(_environment, owner, template, namespace) {
643
+ this._environment = _environment;
644
+ this.owner = owner;
645
+ this.template = template;
646
+ this.namespace = namespace;
647
+ let outletStateTag = createTag();
648
+ let outletState = {
649
+ outlets: {
650
+ main: undefined
651
+ },
652
+ render: {
653
+ owner: owner,
654
+ name: TOP_LEVEL_NAME,
655
+ controller: undefined,
656
+ model: undefined,
657
+ template
658
+ }
659
+ };
660
+ let ref = this.ref = createComputeRef(() => {
661
+ consumeTag(outletStateTag);
662
+ return outletState;
663
+ }, state => {
664
+ DIRTY_TAG$1(outletStateTag);
665
+ outletState.outlets['main'] = state;
666
+ });
667
+ this.state = {
668
+ ref,
669
+ name: TOP_LEVEL_NAME,
670
+ template,
671
+ controller: undefined
672
+ };
673
+ }
674
+ appendTo(selector) {
675
+ let target;
676
+ if (this._environment.hasDOM) {
677
+ target = typeof selector === 'string' ? document.querySelector(selector) : selector;
678
+ } else {
679
+ target = selector;
680
+ }
681
+ let renderer = this.owner.lookup('renderer:-dom');
682
+
683
+ // SAFETY: It's not clear that this cast is safe.
684
+ // The types for appendOutletView may be incorrect or this is a potential bug.
685
+ schedule('render', renderer, 'appendOutletView', this, target);
686
+ }
687
+ rerender() {
688
+ /**/
689
+ }
690
+ setOutletState(state) {
691
+ updateRef(this.ref, state);
692
+ }
693
+ destroy() {
694
+ /**/
695
+ }
696
+ }
697
+
698
+ class DynamicScope {
699
+ constructor(view, outletState) {
700
+ this.view = view;
701
+ this.outletState = outletState;
702
+ }
703
+ child() {
704
+ return new DynamicScope(this.view, this.outletState);
705
+ }
706
+ get(key) {
707
+ (!(key === 'outletState') && assert(`Using \`-get-dynamic-scope\` is only supported for \`outletState\` (you used \`${key}\`).`, key === 'outletState'));
708
+ return this.outletState;
709
+ }
710
+ set(key, value) {
711
+ (!(key === 'outletState') && assert(`Using \`-with-dynamic-scope\` is only supported for \`outletState\` (you used \`${key}\`).`, key === 'outletState'));
712
+ this.outletState = value;
713
+ return value;
714
+ }
715
+ }
716
+ class ClassicRootState {
717
+ type = 'classic';
718
+ id;
719
+ result;
720
+ destroyed;
721
+ render;
722
+ env;
723
+ constructor(root, context, owner, template, self, parentElement, dynamicScope, builder) {
724
+ this.root = root;
725
+ (!(template !== undefined) && assert(`You cannot render \`${valueForRef(self)}\` without a template.`, template !== undefined));
726
+ this.id = root instanceof OutletView ? guidFor(root) : getViewId(root);
727
+ this.result = undefined;
728
+ this.destroyed = false;
729
+ this.env = context.env;
730
+ this.render = errorLoopTransaction(() => {
731
+ let layout = unwrapTemplate(template).asLayout();
732
+ let iterator = renderMain(context, owner, self, builder(context.env, {
733
+ element: parentElement,
734
+ nextSibling: null
735
+ }), layout, dynamicScope);
736
+ let result = this.result = iterator.sync();
737
+ associateDestroyableChild(this, result);
738
+ this.render = errorLoopTransaction(() => {
739
+ if (isDestroying(result) || isDestroyed(result)) return;
740
+ return result.rerender({
741
+ alwaysRevalidate: false
742
+ });
743
+ });
744
+ });
745
+ }
746
+ isFor(possibleRoot) {
747
+ return this.root === possibleRoot;
748
+ }
749
+ destroy() {
750
+ let {
751
+ result,
752
+ env
753
+ } = this;
754
+ this.destroyed = true;
755
+ this.root = null;
756
+ this.result = undefined;
757
+ this.render = undefined;
758
+ if (result !== undefined) {
759
+ /*
760
+ Handles these scenarios:
761
+ * When roots are removed during standard rendering process, a transaction exists already
762
+ `.begin()` / `.commit()` are not needed.
763
+ * When roots are being destroyed manually (`component.append(); component.destroy() case), no
764
+ transaction exists already.
765
+ * When roots are being destroyed during `Renderer#destroy`, no transaction exists
766
+ */
767
+
768
+ inTransaction(env, () => destroy(result));
769
+ }
770
+ }
771
+ }
772
+ class Renderer extends BaseRenderer {
773
+ _rootTemplate;
774
+ _viewRegistry;
775
+ static create(props) {
776
+ let {
777
+ _viewRegistry
778
+ } = props;
779
+ let owner = getOwner(props);
780
+ (!(owner) && assert('Renderer is unexpectedly missing an owner', owner));
781
+ let document = owner.lookup('service:-document');
782
+ let env = owner.lookup('-environment:main');
783
+ let rootTemplate = owner.lookup(privatize`template:-root`);
784
+ let builder = owner.lookup('service:-dom-builder');
785
+ return new this(owner, document, env, rootTemplate, _viewRegistry, builder);
786
+ }
787
+ constructor(owner, document, env, rootTemplate, viewRegistry, builder = clientBuilder, resolver = new RouterResolver()) {
788
+ super(owner, env, document, resolver, builder);
789
+ this._rootTemplate = rootTemplate(owner);
790
+ this._viewRegistry = viewRegistry || owner.lookup('-view-registry:main');
791
+ }
792
+
793
+ // renderer HOOKS
794
+
795
+ appendOutletView(view, target) {
796
+ // TODO: This bypasses the {{outlet}} syntax so logically duplicates
797
+ // some of the set up code. Since this is all internal (or is it?),
798
+ // we can refactor this to do something more direct/less convoluted
799
+ // and with less setup, but get it working first
800
+ let outlet = createRootOutlet(view);
801
+ let {
802
+ name,
803
+ /* controller, */template
804
+ } = view.state;
805
+ let named = dict();
806
+ named['Component'] = createConstRef(makeRouteTemplate(view.owner, name, template), '@Component');
807
+
808
+ // TODO: is this guaranteed to be undefined? It seems to be the
809
+ // case in the `OutletView` class. Investigate how much that class
810
+ // exists as an internal implementation detail only, or if it was
811
+ // used outside of core. As far as I can tell, test-helpers uses
812
+ // it but only for `setOutletState`.
813
+ // named['controller'] = createConstRef(controller, '@controller');
814
+ // Update: at least according to the debug render tree tests, we
815
+ // appear to always expect this to be undefined. Not a definitive
816
+ // source by any means, but is useful evidence
817
+ named['controller'] = UNDEFINED_REFERENCE;
818
+ named['model'] = UNDEFINED_REFERENCE;
819
+ let args = createCapturedArgs(named, EMPTY_POSITIONAL);
820
+ this._appendDefinition(view, curry(0, outlet, view.owner, args, true), target);
821
+ }
822
+ appendTo(view, target) {
823
+ let definition = new RootComponentDefinition(view);
824
+ this._appendDefinition(view, curry(0, definition, this.state.owner, null, true), target);
825
+ }
826
+ _appendDefinition(root, definition, target) {
827
+ let self = createConstRef(definition, 'this');
828
+ let dynamicScope = new DynamicScope(null, UNDEFINED_REFERENCE);
829
+ let rootState = new ClassicRootState(root, this.state.context, this.state.owner, this._rootTemplate, self, target, dynamicScope, this.state.builder);
830
+ this.state.renderRoot(rootState, this);
831
+ }
832
+ cleanupRootFor(component) {
833
+ // no need to cleanup roots if we have already been destroyed
834
+ if (isDestroyed(this)) {
835
+ return;
836
+ }
837
+ let roots = this.state.roots;
838
+
839
+ // traverse in reverse so we can remove items
840
+ // without mucking up the index
841
+ let i = roots.length;
842
+ while (i--) {
843
+ let root = roots[i];
844
+ (!(root) && assert('has root', root));
845
+ if (root.type === 'classic' && root.isFor(component)) {
846
+ root.destroy();
847
+ roots.splice(i, 1);
848
+ }
849
+ }
850
+ }
851
+ remove(view) {
852
+ view._transitionTo('destroying');
853
+ this.cleanupRootFor(view);
854
+ if (this.state.isInteractive) {
855
+ view.trigger('didDestroyElement');
856
+ }
857
+ }
858
+ get _roots() {
859
+ return this.state.debug.roots;
860
+ }
861
+ get _inRenderTransaction() {
862
+ return this.state.debug.inRenderTransaction;
863
+ }
864
+ get _isInteractive() {
865
+ return this.state.debug.isInteractive;
866
+ }
867
+ get _context() {
868
+ return this.state.context;
869
+ }
870
+ register(view) {
871
+ let id = getViewId(view);
872
+ (!(!this._viewRegistry[id]) && assert('Attempted to register a view with an id already in use: ' + id, !this._viewRegistry[id]));
873
+ this._viewRegistry[id] = view;
874
+ }
875
+ unregister(view) {
876
+ delete this._viewRegistry[getViewId(view)];
877
+ }
878
+ getElement(component) {
879
+ if (this._isInteractive) {
880
+ return getViewElement(component);
881
+ } else {
882
+ throw new Error('Accessing `this.element` is not allowed in non-interactive environments (such as FastBoot).');
883
+ }
884
+ }
885
+ getBounds(component) {
886
+ let bounds = component[BOUNDS];
887
+ (!(bounds) && assert('object passed to getBounds must have the BOUNDS symbol as a property', bounds));
888
+ let parentElement = bounds.parentElement();
889
+ let firstNode = bounds.firstNode();
890
+ let lastNode = bounds.lastNode();
891
+ return {
892
+ parentElement,
893
+ firstNode,
894
+ lastNode
895
+ };
896
+ }
897
+ }
898
+
899
+ const OutletTemplate = templateFactory(
900
+ /*
901
+ {{component (outletHelper)}}
902
+ */
903
+ {
904
+ "id": null,
905
+ "block": "[[[46,[28,[32,0],null,null],null,null,null]],[],[\"component\"]]",
906
+ "moduleName": "packages/@ember/-internals/glimmer/lib/templates/outlet.hbs",
907
+ "scope": () => ({
908
+ outletHelper
909
+ }),
910
+ "isStrictMode": true
911
+ });
912
+
913
+ function setupApplicationRegistry(registry) {
914
+ // because we are using injections we can't use instantiate false
915
+ // we need to use bind() to copy the function so factory for
916
+ // association won't leak
917
+ registry.register('service:-dom-builder', {
918
+ // Additionally, we *must* constrain this to require `props` on create, else
919
+ // we *know* it cannot have an owner.
920
+ create(props) {
921
+ let owner = getOwner(props);
922
+ (!(owner) && assert('DomBuilderService is unexpectedly missing an owner', owner));
923
+ let env = owner.lookup('-environment:main');
924
+ switch (env._renderMode) {
925
+ case 'serialize':
926
+ return serializeBuilder.bind(null);
927
+ case 'rehydrate':
928
+ return rehydrationBuilder.bind(null);
929
+ default:
930
+ return clientBuilder.bind(null);
931
+ }
932
+ }
933
+ });
934
+ registry.register(privatize`template:-root`, RootTemplate);
935
+ registry.register('renderer:-dom', Renderer);
936
+ }
937
+ function setupEngineRegistry(registry) {
938
+ registry.optionsForType('template', {
939
+ instantiate: false
940
+ });
941
+ registry.register('view:-outlet', OutletView);
942
+ registry.register('template:-outlet', OutletTemplate);
943
+ registry.optionsForType('helper', {
944
+ instantiate: false
945
+ });
946
+ registry.register('component:input', Input);
947
+ registry.register('component:link-to', LinkTo);
948
+ registry.register('component:textarea', Textarea);
949
+ }
950
+
951
+ export { OutletView as O, Renderer as R, RootTemplate as a, setupEngineRegistry as b, setupApplicationRegistry as s };