@absolutejs/absolute 0.19.0-beta.871 → 0.19.0-beta.873

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.
@@ -15,18 +15,22 @@ import type {} from '../../../types/globals';
15
15
  * detached root.
16
16
  *
17
17
  * Caveats baked into this approach:
18
- * • The new LView starts as a "root" view (createComponent attaches
19
- * it to ApplicationRef). After splice, it's a child of the
20
- * original parent. We need to detach from ApplicationRef so it's
21
- * not double-tracked.
22
18
  * • Old @Input bindings from the parent are NOT re-applied. The
23
19
  * parent's template flow runs at parent-CD time and wires inputs
24
20
  * then; until then the new instance sees default values. In
25
21
  * practice this matches Tier 1 rebootstrap behavior — no worse.
26
22
  * • Old projection content (ng-content) doesn't transfer. If the
27
23
  * parent injected a child via ng-content, the new instance has an
28
- * empty projection slot until parent re-renders. Logged as a
29
- * known limitation in ANGULAR_PER_COMPONENT_REMOUNT_RESEARCH.md. */
24
+ * empty projection slot until parent re-renders.
25
+ * Class field initializers (e.g. `private foo = inject(Bar)`) are
26
+ * baked into the original class's compiled constructor at bundle
27
+ * time. The surgical update patches `Class.ɵcmp` and prototype
28
+ * methods, but does NOT replace the class itself — so a NEW field
29
+ * added in source after the initial bundle won't appear on the
30
+ * fresh instance. Method-body / decorator / provider / template
31
+ * changes DO take effect (they live on the def, not the
32
+ * constructor). To pick up new field initializers requires a
33
+ * class-level rewrite or escalation to Tier 1b rebootstrap. */
30
34
 
31
35
  import {
32
36
  CONTEXT,
@@ -173,20 +177,6 @@ const teardownOldLView = (oldLView: LView): void => {
173
177
  markLViewDestroyed(oldLView);
174
178
  };
175
179
 
176
- /* The fresh ComponentRef is registered as a root view on
177
- * ApplicationRef. We don't want it tracked there — its parent in the
178
- * view tree is the original parent LView. Detach it. */
179
- const detachFromApplicationRoot = (
180
- componentRef: { hostView: unknown },
181
- core: AngularCoreNamespace
182
- ): void => {
183
- if (!core.ApplicationRef) return;
184
- const w = window as unknown as {
185
- __ANGULAR_APP__?: { detachView?: (view: unknown) => void };
186
- };
187
- w.__ANGULAR_APP__?.detachView?.(componentRef.hostView);
188
- };
189
-
190
180
  export type RemountResult = {
191
181
  className: string;
192
182
  remounted: number;
@@ -212,14 +202,29 @@ export const remountComponentClass = async (
212
202
  Class: unknown,
213
203
  namespaces: unknown[],
214
204
  ...locals: unknown[]
215
- ) => void,
205
+ ) => unknown,
216
206
  namespaces: unknown[],
217
207
  locals: unknown[],
218
208
  core: AngularCoreNamespace,
219
209
  className: string
220
210
  ): Promise<RemountResult> => {
211
+ let FreshClass: ComponentClass = Class;
221
212
  try {
222
- applyMetadata.apply(null, [Class, namespaces, ...locals]);
213
+ // `applyMetadata` from a recent fastHmr build returns a `_Fresh`
214
+ // class with the new constructor + field initializers + the
215
+ // live class's `ɵcmp` re-bound. Older builds (or non-component
216
+ // surgical paths) return undefined; in that case the live
217
+ // class is used and `createComponent` will call its existing
218
+ // factory — no field-initializer refresh, but template /
219
+ // method patches still apply.
220
+ const returned = applyMetadata.apply(null, [
221
+ Class,
222
+ namespaces,
223
+ ...locals
224
+ ]);
225
+ if (typeof returned === 'function') {
226
+ FreshClass = returned as ComponentClass;
227
+ }
223
228
  } catch (err) {
224
229
  return {
225
230
  className,
@@ -239,14 +244,13 @@ export const remountComponentClass = async (
239
244
 
240
245
  for (const target of targets) {
241
246
  try {
242
- const fresh = createFreshAt(Class, target.host, core);
247
+ const fresh = createFreshAt(FreshClass, target.host, core);
243
248
  if (!fresh) {
244
249
  skipped++;
245
250
  continue;
246
251
  }
247
252
 
248
253
  spliceLViewIntoParent(target, fresh.newLView);
249
- detachFromApplicationRoot(fresh.componentRef, core);
250
254
  teardownOldLView(target.oldLView);
251
255
 
252
256
  fresh.componentRef.hostView.detectChanges?.();
package/dist/index.js CHANGED
@@ -9832,7 +9832,31 @@ __export(exports_hmrInjectionPlugin, {
9832
9832
  });
9833
9833
  import { readFile as readFile5 } from "fs/promises";
9834
9834
  import { relative as relative6, resolve as resolve15 } from "path";
9835
- var ENTITY_DECORATOR_RE, buildHmrTail = (className, encodedIdLiteral) => `
9835
+ var ENTITY_DECORATOR_RE, IMPORT_RE, extractImportedLocalNames = (jsSource) => {
9836
+ const names = new Set;
9837
+ IMPORT_RE.lastIndex = 0;
9838
+ let match;
9839
+ while ((match = IMPORT_RE.exec(jsSource)) !== null) {
9840
+ const [, , nsName, defaultName, namedAfterDefault, named] = match;
9841
+ if (nsName)
9842
+ names.add(nsName);
9843
+ if (defaultName)
9844
+ names.add(defaultName);
9845
+ const namedClause = namedAfterDefault ?? named;
9846
+ if (namedClause) {
9847
+ for (const part of namedClause.split(",")) {
9848
+ const trimmed = part.trim();
9849
+ if (!trimmed)
9850
+ continue;
9851
+ const asIdx = trimmed.search(/\s+as\s+/);
9852
+ const local = asIdx >= 0 ? trimmed.slice(asIdx).replace(/^\s+as\s+/, "").trim() : trimmed;
9853
+ if (/^[A-Za-z_$][\w$]*$/.test(local))
9854
+ names.add(local);
9855
+ }
9856
+ }
9857
+ }
9858
+ return [...names];
9859
+ }, buildHmrTail = (className, encodedIdLiteral) => `
9836
9860
 
9837
9861
  // absolutejs HMR \u2014 auto-generated; mirrors compileHmrInitializer from
9838
9862
  // @angular/compiler with import.meta.hot adapted to globalThis.__angularHmr.
@@ -9953,13 +9977,22 @@ var ENTITY_DECORATOR_RE, buildHmrTail = (className, encodedIdLiteral) => `
9953
9977
  const id = `${projectRel}@${className}`;
9954
9978
  return buildHmrTail(className, JSON.stringify(id));
9955
9979
  }).join("");
9956
- return { contents: text + tail, loader: "js" };
9980
+ const importedLocalNames = extractImportedLocalNames(text);
9981
+ const depsKeys = importedLocalNames.filter((n) => !classNames.includes(n)).join(", ");
9982
+ const depsBlock = classNames.length > 0 && depsKeys ? `
9983
+
9984
+ // absolutejs HMR \u2014 Tier 1a class-deps registry
9985
+ ` + classNames.map((c) => `try { ${c}.__abs_deps = { ${depsKeys} }; } catch {}`).join(`
9986
+ `) + `
9987
+ ` : "";
9988
+ return { contents: text + tail + depsBlock, loader: "js" };
9957
9989
  });
9958
9990
  }
9959
9991
  };
9960
9992
  };
9961
9993
  var init_hmrInjectionPlugin = __esm(() => {
9962
9994
  ENTITY_DECORATOR_RE = /([A-Z][A-Za-z0-9_$]*)\s*=\s*__legacyDecorateClassTS[A-Za-z0-9_$]*\s*\(\s*\[[\s\S]*?\b(?:Component|Directive|Pipe|Injectable)[A-Za-z0-9_$]*\s*\(/g;
9995
+ IMPORT_RE = /^\s*import\s+(?:(?:(\*)\s+as\s+([A-Za-z_$][\w$]*)\s+from)|(?:([A-Za-z_$][\w$]*)(?:\s*,\s*\{([^}]*)\})?\s+from)|(?:\{([^}]*)\}\s+from))\s*['"][^'"]+['"]/gm;
9963
9996
  });
9964
9997
 
9965
9998
  // src/utils/cleanStaleOutputs.ts
@@ -18854,10 +18887,22 @@ var fail = (reason, detail) => ({ ok: false, reason, detail }), fingerprintCache
18854
18887
  standalone: decoratorMeta.standalone
18855
18888
  };
18856
18889
  }, buildFreshClassMethodsBlock = (classNode, className) => {
18857
- const methodSources = [];
18890
+ const memberSources = [];
18858
18891
  let hasStatic = false;
18859
18892
  const printer = ts7.createPrinter({ removeComments: true });
18860
18893
  for (const member of classNode.members) {
18894
+ if (ts7.isPropertyDeclaration(member)) {
18895
+ const modifiers = (ts7.getModifiers(member) ?? []).filter((m) => m.kind !== ts7.SyntaxKind.Decorator && m.kind !== ts7.SyntaxKind.PrivateKeyword && m.kind !== ts7.SyntaxKind.PublicKeyword && m.kind !== ts7.SyntaxKind.ProtectedKeyword && m.kind !== ts7.SyntaxKind.ReadonlyKeyword && m.kind !== ts7.SyntaxKind.OverrideKeyword);
18896
+ const cleaned = ts7.factory.createPropertyDeclaration(modifiers, member.name, undefined, undefined, member.initializer);
18897
+ memberSources.push(printer.printNode(ts7.EmitHint.Unspecified, cleaned, classNode.getSourceFile()));
18898
+ continue;
18899
+ }
18900
+ if (ts7.isConstructorDeclaration(member)) {
18901
+ const cleanedParams = member.parameters.map((param) => ts7.factory.updateParameterDeclaration(param, (ts7.getModifiers(param) ?? []).filter((m) => m.kind !== ts7.SyntaxKind.Decorator && m.kind !== ts7.SyntaxKind.PrivateKeyword && m.kind !== ts7.SyntaxKind.PublicKeyword && m.kind !== ts7.SyntaxKind.ProtectedKeyword && m.kind !== ts7.SyntaxKind.ReadonlyKeyword && m.kind !== ts7.SyntaxKind.OverrideKeyword), param.dotDotDotToken, param.name, param.questionToken, param.type, param.initializer));
18902
+ const cleaned = ts7.factory.createConstructorDeclaration([], cleanedParams, member.body);
18903
+ memberSources.push(printer.printNode(ts7.EmitHint.Unspecified, cleaned, classNode.getSourceFile()));
18904
+ continue;
18905
+ }
18861
18906
  if (ts7.isMethodDeclaration(member) || ts7.isGetAccessorDeclaration(member) || ts7.isSetAccessorDeclaration(member)) {
18862
18907
  const modifiers = ts7.getModifiers(member) ?? [];
18863
18908
  const isStatic = modifiers.some((m) => m.kind === ts7.SyntaxKind.StaticKeyword);
@@ -18873,13 +18918,13 @@ var fail = (reason, detail) => ({ ok: false, reason, detail }), fingerprintCache
18873
18918
  cleaned = ts7.factory.createSetAccessorDeclaration(modifiers.filter((m) => m.kind !== ts7.SyntaxKind.Decorator), member.name, cleanedParams, member.body);
18874
18919
  }
18875
18920
  const printed = printer.printNode(ts7.EmitHint.Unspecified, cleaned, classNode.getSourceFile());
18876
- methodSources.push(printed);
18921
+ memberSources.push(printed);
18877
18922
  }
18878
18923
  }
18879
- if (methodSources.length === 0)
18924
+ if (memberSources.length === 0)
18880
18925
  return null;
18881
18926
  const wrappedSource = `class _Fresh {
18882
- ${methodSources.join(`
18927
+ ${memberSources.join(`
18883
18928
  `)}
18884
18929
  }`;
18885
18930
  let transpiled;
@@ -19118,55 +19163,59 @@ ${block}
19118
19163
  while ((idMatch = identRe.exec(provisionalMethodsBlock)) !== null) {
19119
19164
  referencedNames.add(idMatch[0]);
19120
19165
  }
19121
- const importDecls = [];
19166
+ const sourceImportedNames = new Set;
19122
19167
  for (const stmt of sourceFile.statements) {
19123
19168
  if (!ts7.isImportDeclaration(stmt))
19124
19169
  continue;
19125
19170
  if (!ts7.isStringLiteral(stmt.moduleSpecifier))
19126
19171
  continue;
19127
- const spec = stmt.moduleSpecifier.text;
19128
- if (spec.startsWith(".") || spec.startsWith("/"))
19129
- continue;
19130
- const importedNames = [];
19131
19172
  const clause = stmt.importClause;
19132
19173
  if (clause?.name)
19133
- importedNames.push(clause.name.text);
19174
+ sourceImportedNames.add(clause.name.text);
19134
19175
  if (clause?.namedBindings && ts7.isNamedImports(clause.namedBindings)) {
19135
19176
  for (const el of clause.namedBindings.elements) {
19136
19177
  if (el.isTypeOnly)
19137
19178
  continue;
19138
- importedNames.push(el.name.text);
19179
+ sourceImportedNames.add(el.name.text);
19139
19180
  }
19140
19181
  } else if (clause?.namedBindings && ts7.isNamespaceImport(clause.namedBindings)) {
19141
- importedNames.push(clause.namedBindings.name.text);
19182
+ sourceImportedNames.add(clause.namedBindings.name.text);
19142
19183
  }
19143
- if (!importedNames.some((n) => referencedNames.has(n)))
19144
- continue;
19145
- importDecls.push(printer.printNode(ts7.EmitHint.Unspecified, stmt, sourceFile));
19146
19184
  }
19147
- const tsSourceText = (importDecls.length > 0 ? importDecls.join(`
19148
- `) + `
19149
-
19150
- ` : "") + fnText;
19185
+ const depsToDestructure = [...sourceImportedNames].filter((n) => referencedNames.has(n));
19186
+ const tsSourceText = fnText;
19151
19187
  const transpiled = ts7.transpileModule(tsSourceText, {
19152
19188
  compilerOptions: {
19153
19189
  module: ts7.ModuleKind.ES2022,
19154
- target: ts7.ScriptTarget.ES2022,
19155
- verbatimModuleSyntax: true
19190
+ target: ts7.ScriptTarget.ES2022
19156
19191
  },
19157
19192
  fileName: componentFilePath,
19158
19193
  reportDiagnostics: false
19159
19194
  }).outputText;
19160
19195
  const methodsBlock = buildFreshClassMethodsBlock(classNode, className);
19161
19196
  let moduleText = transpiled;
19162
- if (methodsBlock) {
19163
- const fnOpening = `function ${className}_UpdateMetadata(${className}, \u0275\u0275namespaces) {`;
19164
- const idx = moduleText.indexOf(fnOpening);
19165
- if (idx >= 0) {
19166
- const insertAt = idx + fnOpening.length;
19167
- moduleText = moduleText.slice(0, insertAt) + `
19197
+ const fnOpening = `function ${className}_UpdateMetadata(${className}, \u0275\u0275namespaces) {`;
19198
+ const fnOpeningIdx = moduleText.indexOf(fnOpening);
19199
+ const depsDestructure = depsToDestructure.length > 0 ? `
19200
+ const { ${depsToDestructure.join(", ")} } = ${className}.__abs_deps || {};
19201
+ ` : "";
19202
+ if (fnOpeningIdx >= 0 && (methodsBlock || depsDestructure)) {
19203
+ const insertAt = fnOpeningIdx + fnOpening.length;
19204
+ moduleText = moduleText.slice(0, insertAt) + depsDestructure + (methodsBlock ? `
19168
19205
  ` + methodsBlock + `
19169
- ` + moduleText.slice(insertAt);
19206
+ ` : "") + moduleText.slice(insertAt);
19207
+ }
19208
+ if (methodsBlock) {
19209
+ const tail = `
19210
+ if (typeof _Fresh !== 'undefined') {
19211
+ _Fresh.\u0275cmp = ${className}.\u0275cmp;
19212
+ _Fresh.\u0275fac = function() { return new _Fresh(); };
19213
+ return _Fresh;
19214
+ }
19215
+ `;
19216
+ const lastBrace = moduleText.lastIndexOf("}");
19217
+ if (lastBrace >= 0) {
19218
+ moduleText = moduleText.slice(0, lastBrace) + tail + moduleText.slice(lastBrace);
19170
19219
  }
19171
19220
  }
19172
19221
  fingerprintCache.set(fingerprintId, currentFingerprint);
@@ -21974,9 +22023,14 @@ var STORE_KEY = "__elysiaStore", getGlobalValue = (key) => Reflect.get(globalThi
21974
22023
  if (module === null) {
21975
22024
  return new Response(`No HMR module for id=${id}. The component may not be in the current program, or the program isn't built yet (rebuild on first save).`, { status: 404 });
21976
22025
  }
21977
- const { getDevVendorPaths: getDevVendorPaths2 } = await Promise.resolve().then(() => exports_devVendorPaths);
22026
+ const { getDevVendorPaths: getDevVendorPaths2, getAngularVendorPaths: getAngularVendorPaths2 } = await Promise.resolve().then(() => exports_devVendorPaths);
21978
22027
  const { rewriteImportsInContent: rewriteImportsInContent2 } = await Promise.resolve().then(() => (init_rewriteImportsPlugin(), exports_rewriteImportsPlugin));
21979
- const vendorPaths = getDevVendorPaths2() ?? {};
22028
+ const depVendorPaths = globalThis.__depVendorPaths ?? {};
22029
+ const vendorPaths = {
22030
+ ...getDevVendorPaths2() ?? {},
22031
+ ...getAngularVendorPaths2() ?? {},
22032
+ ...depVendorPaths
22033
+ };
21980
22034
  const rewritten = rewriteImportsInContent2(module, vendorPaths);
21981
22035
  return new Response(rewritten, {
21982
22036
  headers: {
@@ -30400,5 +30454,5 @@ export {
30400
30454
  ANGULAR_INIT_TIMEOUT_MS
30401
30455
  };
30402
30456
 
30403
- //# debugId=CE269C6EA595A26164756E2164756E21
30457
+ //# debugId=318C2BB565882B2764756E2164756E21
30404
30458
  //# sourceMappingURL=index.js.map