-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
imports.ts
101 lines (91 loc) · 3.37 KB
/
imports.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import { dirname, isAbsolute, join, relative, resolve } from 'path';
import parse from 'parse-filepath';
export type ImportDeclaration<T = string> = {
outputPath: string;
importSource: ImportSource<T>;
baseOutputDir: string;
baseDir: string;
typesImport: boolean;
emitLegacyCommonJSImports: boolean;
};
export type ImportSource<T = string> = {
/**
* Source path, relative to the `baseOutputDir`
*/
path: string;
/**
* Namespace to import source as
*/
namespace?: string;
/**
* Entity names to import
*/
identifiers?: T[];
};
export type FragmentImport = {
name: string;
kind: 'type' | 'document';
};
export function generateFragmentImportStatement(
statement: ImportDeclaration<FragmentImport>,
kind: 'type' | 'document' | 'both'
): string {
const { importSource: fragmentImportSource, ...rest } = statement;
const { identifiers, path, namespace } = fragmentImportSource;
const importSource: ImportSource<string> = {
identifiers: identifiers
.filter(fragmentImport => kind === 'both' || kind === fragmentImport.kind)
.map(({ name }) => name),
path,
namespace,
};
return generateImportStatement({
importSource,
...rest,
typesImport: kind === 'type' ? statement.typesImport : false,
});
}
export function generateImportStatement(statement: ImportDeclaration): string {
const { baseDir, importSource, outputPath, typesImport } = statement;
const importPath = resolveImportPath(baseDir, outputPath, importSource.path);
const importNames =
importSource.identifiers && importSource.identifiers.length
? `{ ${Array.from(new Set(importSource.identifiers)).join(', ')} }`
: '*';
const importExtension =
importPath.startsWith('/') || importPath.startsWith('.') ? (statement.emitLegacyCommonJSImports ? '' : '.js') : '';
const importAlias = importSource.namespace ? ` as ${importSource.namespace}` : '';
const importStatement = typesImport ? 'import type' : 'import';
return `${importStatement} ${importNames}${importAlias} from '${importPath}${importExtension}';${
importAlias ? '\n' : ''
}`;
// return `${importStatement} ${importNames}${importAlias} from '${importPath}';${importAlias ? '\n' : ''}`;
}
function resolveImportPath(baseDir: string, outputPath: string, sourcePath: string) {
const shouldAbsolute = !sourcePath.startsWith('~');
if (shouldAbsolute) {
const absGeneratedFilePath = resolve(baseDir, outputPath);
const absImportFilePath = resolve(baseDir, sourcePath);
return resolveRelativeImport(absGeneratedFilePath, absImportFilePath);
}
return sourcePath.replace(`~`, '');
}
export function resolveRelativeImport(from: string, to: string): string {
if (!isAbsolute(from)) {
throw new Error(`Argument 'from' must be an absolute path, '${from}' given.`);
}
if (!isAbsolute(to)) {
throw new Error(`Argument 'to' must be an absolute path, '${to}' given.`);
}
return fixLocalFilePath(clearExtension(relative(dirname(from), to)));
}
export function resolveImportSource<T>(source: string | ImportSource<T>): ImportSource<T> {
return typeof source === 'string' ? { path: source } : source;
}
export function clearExtension(path: string): string {
const parsedPath = parse(path);
return join(parsedPath.dir, parsedPath.name).replace(/\\/g, '/');
}
export function fixLocalFilePath(path: string): string {
return !path.startsWith('..') ? `./${path}` : path;
}