@postxl/generator 1.0.7 → 1.0.8

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.
@@ -1,5 +1,12 @@
1
1
  import { NonEmptyArray } from '@postxl/utils';
2
2
  import * as Brands from './branded.types';
3
+ /**
4
+ * An import item that can optionally have an alias.
5
+ */
6
+ export type ImportItem = Brands.ImportableTypes | {
7
+ name: Brands.ImportableTypes;
8
+ alias: string;
9
+ };
3
10
  /**
4
11
  * A structured definition of multiple imports: The key of the object is the "from" path,
5
12
  * the value is a list (or single item) of items to import.
@@ -12,7 +19,7 @@ import * as Brands from './branded.types';
12
19
  * }
13
20
  * ```
14
21
  */
15
- export type BulkImportDefinition = Record<Brands.ImportPaths, NonEmptyArray<Brands.ImportableTypes> | Brands.ImportableTypes>;
22
+ export type BulkImportDefinition = Record<Brands.ImportPaths, NonEmptyArray<ImportItem> | ImportItem>;
16
23
  /**
17
24
  * A utility component that lets you generate TypeScript import statements
18
25
  * and makes sure every import is only added once.
@@ -29,29 +36,46 @@ export declare class ImportGenerator {
29
36
  /**
30
37
  * Convenience method to add a single import statement.
31
38
  */
32
- add({ name, location }: {
39
+ add({ name, location, alias, }: {
33
40
  name: Brands.ImportableTypes;
34
41
  location: Brands.ImportPaths;
42
+ alias?: string;
35
43
  }): this;
36
44
  /**
37
45
  * Convenience method to add a single import statement.
38
46
  */
39
- addType({ name, location }: {
47
+ addType({ name, location, alias, }: {
40
48
  name: Brands.TypeName;
41
49
  location: Brands.ImportPaths;
50
+ alias?: string;
42
51
  }): this;
43
52
  /**
44
53
  * Adds a given import statement to the imports list.
45
54
  */
46
- addImport({ items, from: fromSource, }: {
47
- items: NonEmptyArray<Brands.ImportableTypes>;
55
+ addImport({ items, from: fromSource }: {
56
+ items: NonEmptyArray<ImportItem>;
48
57
  from: Brands.ImportPaths;
49
58
  }): this;
59
+ /**
60
+ * Creates a unique key for an import based on name and alias.
61
+ */
62
+ private makeImportKey;
63
+ /**
64
+ * Validates that an alias is not an empty string.
65
+ */
66
+ private validateAlias;
67
+ /**
68
+ * Normalizes an import item to extract name and optional alias.
69
+ */
70
+ private normalizeImportItem;
50
71
  /**
51
72
  * Adds a given type import statement to the imports list.
52
73
  */
53
- addTypeImport({ items, from }: {
54
- items: NonEmptyArray<Brands.TypeName>;
74
+ addTypeImport({ items, from, }: {
75
+ items: NonEmptyArray<Brands.TypeName | {
76
+ name: Brands.TypeName;
77
+ alias: string;
78
+ }>;
55
79
  from: Brands.ImportPaths;
56
80
  }): this;
57
81
  /**
@@ -50,6 +50,18 @@ const Brands = __importStar(require("./branded.types"));
50
50
  // */
51
51
  // packageName?: Brands.PackageName
52
52
  // }
53
+ /**
54
+ * Type guard to check if an import item has an alias.
55
+ */
56
+ function isImportItemWithAlias(item) {
57
+ return typeof item === 'object' && 'name' in item && 'alias' in item && typeof item.alias === 'string';
58
+ }
59
+ /**
60
+ * Type guard to check if a type import item has an alias.
61
+ */
62
+ function isTypeImportItemWithAlias(item) {
63
+ return typeof item === 'object' && 'name' in item && 'alias' in item && typeof item.alias === 'string';
64
+ }
53
65
  /**
54
66
  * A utility component that lets you generate TypeScript import statements
55
67
  * and makes sure every import is only added once.
@@ -57,6 +69,7 @@ const Brands = __importStar(require("./branded.types"));
57
69
  class ImportGenerator {
58
70
  /**
59
71
  * Lists of values and types we import from a given path indexed by the path.
72
+ * Maps a unique key (name::alias) to the import details.
60
73
  */
61
74
  #imports = {};
62
75
  /**
@@ -75,19 +88,25 @@ class ImportGenerator {
75
88
  /**
76
89
  * Convenience method to add a single import statement.
77
90
  */
78
- add({ name, location }) {
79
- return this.addImport({ items: [name], from: location });
91
+ add({ name, location, alias, }) {
92
+ if (alias !== undefined) {
93
+ this.validateAlias(alias);
94
+ }
95
+ return this.addImport({ items: [alias ? { name, alias } : name], from: location });
80
96
  }
81
97
  /**
82
98
  * Convenience method to add a single import statement.
83
99
  */
84
- addType({ name, location }) {
85
- return this.addTypeImport({ items: [name], from: location });
100
+ addType({ name, location, alias, }) {
101
+ if (alias !== undefined) {
102
+ this.validateAlias(alias);
103
+ }
104
+ return this.addTypeImport({ items: [alias ? { name, alias } : name], from: location });
86
105
  }
87
106
  /**
88
107
  * Adds a given import statement to the imports list.
89
108
  */
90
- addImport({ items, from: fromSource, }) {
109
+ addImport({ items, from: fromSource }) {
91
110
  if (items.length === 0) {
92
111
  throw new Error(`You cannot add an import statement without any items from ${fromSource}.`);
93
112
  }
@@ -98,24 +117,57 @@ class ImportGenerator {
98
117
  }
99
118
  const resolvedPath = ImportGenerator.getRelativePath({ from: this.#path, to: from });
100
119
  if (!this.#imports[resolvedPath]) {
101
- this.#imports[resolvedPath] = { types: new Set(), nonTypes: new Set() };
120
+ this.#imports[resolvedPath] = { types: new Map(), nonTypes: new Map() };
102
121
  }
103
122
  items.forEach((item) => {
104
- if (Brands.isAnnotatedTypeName(item)) {
105
- this.#imports[resolvedPath].types.add(item.typeName);
123
+ const { name, alias } = this.normalizeImportItem(item);
124
+ const importName = Brands.isAnnotatedTypeName(name) ? name.typeName : name;
125
+ const key = this.makeImportKey(importName, alias);
126
+ if (Brands.isAnnotatedTypeName(name)) {
127
+ this.#imports[resolvedPath].types.set(key, { name: name.typeName, alias });
106
128
  }
107
129
  else {
108
- this.#imports[resolvedPath].nonTypes.add(item);
130
+ this.#imports[resolvedPath].nonTypes.set(key, { name, alias });
109
131
  }
110
132
  });
111
133
  return this;
112
134
  }
135
+ /**
136
+ * Creates a unique key for an import based on name and alias.
137
+ */
138
+ makeImportKey(name, alias) {
139
+ return alias ? `${name}::${alias}` : name;
140
+ }
141
+ /**
142
+ * Validates that an alias is not an empty string.
143
+ */
144
+ validateAlias(alias) {
145
+ if (alias.trim() === '') {
146
+ throw new Error('Import alias cannot be an empty string');
147
+ }
148
+ }
149
+ /**
150
+ * Normalizes an import item to extract name and optional alias.
151
+ */
152
+ normalizeImportItem(item) {
153
+ if (isImportItemWithAlias(item)) {
154
+ this.validateAlias(item.alias);
155
+ return { name: item.name, alias: item.alias };
156
+ }
157
+ return { name: item, alias: undefined };
158
+ }
113
159
  /**
114
160
  * Adds a given type import statement to the imports list.
115
161
  */
116
- addTypeImport({ items, from }) {
162
+ addTypeImport({ items, from, }) {
117
163
  return this.addImport({
118
- items: items.map((i) => Brands.toAnnotatedTypeName(i)),
164
+ items: items.map((i) => {
165
+ if (isTypeImportItemWithAlias(i)) {
166
+ this.validateAlias(i.alias);
167
+ return { name: Brands.toAnnotatedTypeName(i.name), alias: i.alias };
168
+ }
169
+ return Brands.toAnnotatedTypeName(i);
170
+ }),
119
171
  from,
120
172
  });
121
173
  }
@@ -140,9 +192,13 @@ class ImportGenerator {
140
192
  const statements = Object.entries(this.#imports)
141
193
  .sort(([a], [b]) => a.localeCompare(b))
142
194
  .map(([path, items]) => {
143
- const nonTypes = Array.from(items.nonTypes).sort((a, b) => a.localeCompare(b));
195
+ const nonTypes = Array.from(items.nonTypes.values())
196
+ .sort((a, b) => a.name.localeCompare(b.name))
197
+ .map(({ name, alias }) => (alias ? `${name} as ${alias}` : name));
144
198
  const nonTypesImportStatement = nonTypes.length > 0 ? `import { ${nonTypes.join(', ')} } from '${path}'\n` : '';
145
- const types = Array.from(items.types).sort((a, b) => a.localeCompare(b));
199
+ const types = Array.from(items.types.values())
200
+ .sort((a, b) => a.name.localeCompare(b.name))
201
+ .map(({ name, alias }) => (alias ? `${name} as ${alias}` : name));
146
202
  const typesImportStatement = types.length > 0 ? `import type { ${types.join(', ')} } from '${path}'` : '';
147
203
  return `${nonTypesImportStatement}${typesImportStatement}`;
148
204
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postxl/generator",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Core package that orchestrates the code generation of a PXL project",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",