@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<
|
|
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<
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
120
|
+
this.#imports[resolvedPath] = { types: new Map(), nonTypes: new Map() };
|
|
102
121
|
}
|
|
103
122
|
items.forEach((item) => {
|
|
104
|
-
|
|
105
|
-
|
|
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.
|
|
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) =>
|
|
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
|
|
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
|
|
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
|
})
|