@dunx/transform 2.5.0 → 3.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.
package/dist/ast.d.ts CHANGED
@@ -47,16 +47,30 @@ export interface ImportDeclaration extends Node {
47
47
  readonly specifiers: readonly Node[];
48
48
  readonly importKind: 'value' | 'type';
49
49
  }
50
+ /**
51
+ * `ImportSpecifier`, `ImportDefaultSpecifier` and `ImportNamespaceSpecifier`.
52
+ * Only the first carries its own `importKind`; all three carry `local`, which is
53
+ * the name the file binds and the only field the erasure map needs.
54
+ */
50
55
  export interface ImportSpecifier extends Node {
51
- readonly type: 'ImportSpecifier';
52
56
  readonly local: Identifier;
53
- readonly importKind: 'value' | 'type';
57
+ readonly importKind?: 'value' | 'type';
58
+ }
59
+ export interface TSQualifiedName extends Node {
60
+ readonly type: 'TSQualifiedName';
61
+ readonly left: Node;
62
+ readonly right: Identifier;
63
+ }
64
+ export interface AssignmentPattern extends Node {
65
+ readonly type: 'AssignmentPattern';
66
+ readonly left: Node;
54
67
  }
55
68
  export declare const isIdentifier: (node: Node | null | undefined) => node is Identifier;
56
69
  export declare const isMethodDefinition: (node: Node | null | undefined) => node is MethodDefinition;
57
70
  export declare const isTypeReference: (node: Node | null | undefined) => node is TSTypeReference;
58
71
  export declare const isImportDeclaration: (node: Node | null | undefined) => node is ImportDeclaration;
59
- export declare const isImportSpecifier: (node: Node | null | undefined) => node is ImportSpecifier;
72
+ export declare const isQualifiedName: (node: Node | null | undefined) => node is TSQualifiedName;
73
+ export declare const isAssignmentPattern: (node: Node | null | undefined) => node is AssignmentPattern;
60
74
  export declare const isParameterProperty: (node: Node | null | undefined) => node is TSParameterProperty;
61
75
  /**
62
76
  * Declarations only. A `ClassExpression`'s own name is bound inside the class
@@ -71,3 +85,8 @@ export declare const isClassDeclaration: (node: Node) => node is ClassNode;
71
85
  */
72
86
  export declare const walk: (root: unknown, visit: (node: Node) => void) => void;
73
87
  export declare const nameOf: (node: Node | null | undefined) => string | undefined;
88
+ /**
89
+ * The leftmost identifier of a type name. In `a.b.C` only `a` has to exist at
90
+ * runtime, so it is the only part the erasure map can answer for.
91
+ */
92
+ export declare const rootOfTypeName: (node: Node) => Node;
@@ -23,7 +23,8 @@ var isIdentifier = guard("Identifier");
23
23
  var isMethodDefinition = guard("MethodDefinition");
24
24
  var isTypeReference = guard("TSTypeReference");
25
25
  var isImportDeclaration = guard("ImportDeclaration");
26
- var isImportSpecifier = guard("ImportSpecifier");
26
+ var isQualifiedName = guard("TSQualifiedName");
27
+ var isAssignmentPattern = guard("AssignmentPattern");
27
28
  var isParameterProperty = guard("TSParameterProperty");
28
29
  var isClassDeclaration = (node) => node.type === "ClassDeclaration";
29
30
  var walk = (root, visit) => {
@@ -42,18 +43,33 @@ var walk = (root, visit) => {
42
43
  walk(child, visit);
43
44
  };
44
45
  var nameOf = (node) => isIdentifier(node) ? node.name : undefined;
46
+ var rootOfTypeName = (node) => isQualifiedName(node) ? rootOfTypeName(node.left) : node;
45
47
 
46
48
  // src/erased.ts
49
+ var mergedClassNames = (program) => {
50
+ const body = program.body ?? [];
51
+ const names = new Set;
52
+ for (const statement of body) {
53
+ const declaration = statement.declaration ?? statement;
54
+ if (!isClassDeclaration(declaration))
55
+ continue;
56
+ const name = declaration.id?.name;
57
+ if (name !== undefined)
58
+ names.add(name);
59
+ }
60
+ return names;
61
+ };
47
62
  var collectTypeOnlyNames = (program) => {
48
63
  const names = new Map;
49
64
  walk(program, (node) => {
50
65
  if (isImportDeclaration(node)) {
51
66
  for (const specifier of node.specifiers) {
52
- if (!isImportSpecifier(specifier))
67
+ const { local, importKind } = specifier;
68
+ if (node.importKind !== "type" && importKind !== "type")
53
69
  continue;
54
- if (node.importKind === "type" || specifier.importKind === "type") {
55
- names.set(specifier.local.name, "import-type");
56
- }
70
+ const name = nameOf(local);
71
+ if (name !== undefined)
72
+ names.set(name, "import-type");
57
73
  }
58
74
  return;
59
75
  }
@@ -64,6 +80,8 @@ var collectTypeOnlyNames = (program) => {
64
80
  names.set(name, "declared-type");
65
81
  }
66
82
  });
83
+ for (const name of mergedClassNames(program))
84
+ names.delete(name);
67
85
  return names;
68
86
  };
69
87
  var collectTypeParameters = (klass) => {
@@ -91,23 +109,29 @@ var constructorParams = (klass) => {
91
109
  const found = klass.body.body.find((member) => isMethodDefinition(member) && nameOf(member.key) === "constructor");
92
110
  return isMethodDefinition(found) ? found.value.params : [];
93
111
  };
112
+ var bindingOf = (param) => {
113
+ const named = isParameterProperty(param) ? param.parameter : param;
114
+ return isAssignmentPattern(named) ? named.left : named;
115
+ };
94
116
  var annotationOf = (param) => {
95
- const inner = isParameterProperty(param) ? param.parameter : param;
117
+ const inner = bindingOf(param);
96
118
  if (!isIdentifier(inner))
97
119
  return;
98
120
  return inner.typeAnnotation?.typeAnnotation;
99
121
  };
122
+ var hasDefault = (param) => isAssignmentPattern(isParameterProperty(param) ? param.parameter : param);
100
123
  var entryFor = (source, param, erased) => {
101
124
  const text = JSON.stringify(slice(source, param));
102
- const unresolved = `{ unresolved: ${text} }`;
125
+ const optional = hasDefault(param) ? ", optional: true" : "";
126
+ const unresolved = `{ unresolved: ${text}${optional} }`;
103
127
  const annotation = annotationOf(param);
104
128
  if (!annotation || !isTypeReference(annotation))
105
129
  return unresolved;
106
- const token = slice(source, annotation.typeName);
107
- const cause = erased.get(token);
130
+ const root = nameOf(rootOfTypeName(annotation.typeName));
131
+ const cause = root === undefined ? undefined : erased.get(root);
108
132
  if (cause === undefined)
109
- return token;
110
- return cause === "import-type" ? `{ unresolved: ${text}, typeOnly: ${JSON.stringify(token)} }` : unresolved;
133
+ return slice(source, annotation.typeName);
134
+ return cause === "import-type" ? `{ unresolved: ${text}${optional}, typeOnly: ${JSON.stringify(root)} }` : unresolved;
111
135
  };
112
136
  var transform = (source, filename = "input.ts") => {
113
137
  const parsed = parseSync(filename, source);
@@ -133,10 +157,7 @@ var transform = (source, filename = "input.ts") => {
133
157
  edits.push({
134
158
  start: node.end,
135
159
  end: node.end,
136
- text: `
137
- Object.defineProperty(${name}, ${DEPS_KEY}, {
138
- ` + ` value: () => [${entries.join(", ")}],
139
- });`
160
+ text: `;Object.defineProperty(${name}, ${DEPS_KEY}, ` + `{ value: () => [${entries.join(", ")}] });`
140
161
  });
141
162
  }
142
163
  });
package/dist/edits.d.ts CHANGED
@@ -5,7 +5,8 @@ export interface Edit {
5
5
  }
6
6
  /**
7
7
  * Splices edits into the original text rather than reprinting the AST, so
8
- * everything untouched keeps its exact bytes - comments, formatting, and the
9
- * line numbers stack traces point at.
8
+ * everything untouched keeps its exact bytes. Line numbers survive too, but only
9
+ * because every edit this transform makes is a single line appended to one that
10
+ * already exists - splicing alone does not guarantee it.
10
11
  */
11
12
  export declare const applyEdits: (source: string, edits: readonly Edit[]) => string;
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  applyEdits,
4
4
  depsPlugin,
5
5
  transform
6
- } from "./chunk-41at0m5d.js";
6
+ } from "./chunk-cfmpj4s2.js";
7
7
  export {
8
8
  applyEdits,
9
9
  depsPlugin,
package/dist/preload.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  depsPlugin
4
- } from "./chunk-41at0m5d.js";
4
+ } from "./chunk-cfmpj4s2.js";
5
5
 
6
6
  // src/preload.ts
7
7
  var {plugin } = globalThis.Bun;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dunx/transform",
3
- "version": "2.5.0",
3
+ "version": "3.0.1",
4
4
  "description": "Load-time transform that records constructor dependencies for the dunx container",
5
5
  "keywords": [
6
6
  "bun",