Skip to content

Commit ed8dd9a

Browse files
committed
Read import and another declarations in the svelte code
1 parent 4f5a92a commit ed8dd9a

File tree

5 files changed

+85
-5
lines changed

5 files changed

+85
-5
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@
2929
],
3030
"dependencies": {
3131
"commander": "^7.1.0",
32-
"recursive-readdir": "^2.2.2"
32+
"recursive-readdir": "^2.2.2",
33+
"tmp": "^0.2.1"
3334
},
3435
"devDependencies": {
3536
"@types/estree": "^0.0.46",
3637
"@types/node": "^14.14.30",
38+
"@types/tmp": "^0.2.0",
3739
"estree-walker": "^3.0.0",
3840
"locate-character": "^2.0.5",
3941
"magic-string": "^0.25.7",

src/transformer/svelte.ts

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as ts from 'typescript';
22
import path from 'path';
33
import { promises as fs } from 'fs';
44
import { Ast, TemplateNode } from 'svelte/types/compiler/interfaces';
5+
import tmp from 'tmp';
56
import { Prop, Event, SlotProp } from '../types';
67
import ITransformer from './transformer';
78

@@ -16,6 +17,9 @@ class SvelteTransformer implements ITransformer {
1617
private subdir: string;
1718
private moduleName: string;
1819
private isDefault: boolean;
20+
private typesForSearch: ts.TypeReferenceNode[];
21+
private declarationNode: string[];
22+
private declarationImport: string[];
1923

2024
constructor(content: string, fileName: string, ast: Ast, dir: string, moduleName: string, isDefault: boolean) {
2125
this.sourceFile = ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest);
@@ -28,6 +32,9 @@ class SvelteTransformer implements ITransformer {
2832
this.subdir = path.dirname(this.fileName).replace(this.dir, '');
2933
this.moduleName = moduleName;
3034
this.isDefault = isDefault;
35+
this.typesForSearch = [];
36+
this.declarationNode = [];
37+
this.declarationImport = [];
3138
}
3239

3340
private containExportModifier = (node: ts.VariableStatement): boolean => {
@@ -58,6 +65,10 @@ class SvelteTransformer implements ITransformer {
5865
if (declaration.type) {
5966
type = declaration.type.getText(this.sourceFile);
6067

68+
if (ts.isTypeReferenceNode(declaration.type)) {
69+
this.typesForSearch.push(declaration.type);
70+
}
71+
6172
if (ts.isUnionTypeNode(declaration.type)) {
6273
const nameValidTypes = declaration.type.types.reduce((acc, type) => {
6374
if (type.kind === ts.SyntaxKind.NullKeyword || type.kind === ts.SyntaxKind.UndefinedKeyword) {
@@ -109,6 +120,21 @@ class SvelteTransformer implements ITransformer {
109120
}
110121
}
111122

123+
private verifyImportDeclaration(node: ts.ImportDeclaration, name: string): void {
124+
if (node.importClause && node.importClause.namedBindings && ts.isNamedImports(node.importClause.namedBindings)) {
125+
const elements = node.importClause.namedBindings.elements;
126+
const newElements = elements.filter((element) => element.name.getText(this.sourceFile) === name);
127+
128+
if (newElements.length > 0) {
129+
const importString = newElements.map((item) => item.name.getText(this.sourceFile)).join(', ');
130+
131+
this.declarationImport.push(
132+
`import { ${importString} } from ${node.moduleSpecifier.getText(this.sourceFile)};`
133+
);
134+
}
135+
}
136+
}
137+
112138
exec(): void {
113139
ts.forEachChild(this.sourceFile, (node: ts.Node) => {
114140
if (ts.isVariableStatement(node)) {
@@ -120,10 +146,47 @@ class SvelteTransformer implements ITransformer {
120146
}
121147
});
122148

149+
this.typesForSearch.forEach((item) => {
150+
const name = item.typeName.getText(this.sourceFile);
151+
ts.forEachChild(this.sourceFile, (node: ts.Node) => {
152+
if (ts.isInterfaceDeclaration(node) || ts.isClassDeclaration(node) || ts.isTypeAliasDeclaration(node)) {
153+
if (node.name?.getText(this.sourceFile) === name) {
154+
this.declarationNode.push(node.getText(this.sourceFile));
155+
}
156+
} else if (ts.isImportDeclaration(node)) {
157+
this.verifyImportDeclaration(node, name);
158+
}
159+
});
160+
});
161+
123162
this.execSlotProperty(this.ast.html);
124163
}
125164

126-
toString(): string {
165+
private async toStringDeclarations(): Promise<string> {
166+
const tempFile = tmp.fileSync({ postfix: '.ts' });
167+
const content = this.declarationNode.reduce((acc, item) => `${acc}${item}\n\n`, '');
168+
let declaration = '';
169+
170+
await fs.writeFile(tempFile.name, content);
171+
172+
const options = { declaration: true, emitDeclarationOnly: true };
173+
const host = ts.createCompilerHost(options);
174+
host.writeFile = (_, contents: string) => (declaration = contents);
175+
const program = ts.createProgram([tempFile.name], options, host);
176+
program.emit();
177+
178+
tempFile.removeCallback();
179+
180+
declaration = declaration
181+
.replace(/declare /g, '')
182+
.split('\n')
183+
.map((item) => `\t${item}`)
184+
.join('\n');
185+
186+
return `${declaration}\n`;
187+
}
188+
189+
async toString(): Promise<string> {
127190
const pathParse = path.parse(this.fileName);
128191
const propsString = this.props.reduce(
129192
(acc, prop) => `${acc}\n\t\t${prop.name}${prop.isOptional ? '?' : ''}: ${prop.type};`,
@@ -138,6 +201,15 @@ class SvelteTransformer implements ITransformer {
138201
string = `declare module '${this.moduleName}' {\n`;
139202
}
140203

204+
if (this.declarationImport.length > 0) {
205+
string += this.declarationImport.reduce((acc, item) => `${acc}\t${item}\n`, '');
206+
string += '\n';
207+
}
208+
209+
if (this.declarationNode.length > 0) {
210+
string += await this.toStringDeclarations();
211+
}
212+
141213
string += `\tinterface ${pathParse.name}Props {${propsString}\n\t}\n\n`;
142214
string += `\tclass ${pathParse.name} extends SvelteComponentTyped<\n`;
143215
string += `\t\t${pathParse.name}Props,\n\t\t{ ${eventsString} },\n\t\t{ ${slotPropsString} }\n\t> {}`;
@@ -148,7 +220,7 @@ class SvelteTransformer implements ITransformer {
148220

149221
async appendFile(path: string): Promise<void> {
150222
this.exec();
151-
await fs.appendFile(path, this.toString());
223+
await fs.appendFile(path, await this.toString());
152224
}
153225
}
154226

src/transformer/transformer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
interface ITransformer {
22
exec(): void;
3-
toString(): string;
3+
toString(): string | Promise<string>;
44
appendFile(path: string): Promise<void>;
55
}
66

src/transformer/typescript.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class TypescriptTransformer implements ITransformer {
3939
}
4040

4141
string += this.declaration
42+
.replace(/declare /g, '')
4243
.split('\n')
4344
.map((item) => (item !== '' ? `\t${item}` : undefined))
4445
.filter((item) => !!item)

yarn.lock

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.30.tgz#7d5162eec085ba34f8cb9011e9ba12119f76f961"
2222
integrity sha512-gUWhy8s45fQp4PqqKecsnOkdW0kt1IaKjgOIR3HPokkzTmQj9ji2wWFID5THu1MKrtO+d4s2lVrlEhXUsPXSvg==
2323

24+
"@types/tmp@^0.2.0":
25+
version "0.2.0"
26+
resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.2.0.tgz#e3f52b4d7397eaa9193592ef3fdd44dc0af4298c"
27+
integrity sha512-flgpHJjntpBAdJD43ShRosQvNC0ME97DCfGvZEDlAThQmnerRXrLbX6YgzRBQCZTthET9eAWFAMaYP0m0Y4HzQ==
28+
2429
ansi-styles@^3.2.1:
2530
version "3.2.1"
2631
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
@@ -616,7 +621,7 @@ [email protected]:
616621
resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5"
617622
integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==
618623

619-
624+
[email protected], tmp@^0.2.1:
620625
version "0.2.1"
621626
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
622627
integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==

0 commit comments

Comments
 (0)