forked from getyourguide/vue-class-migrator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmigrator-to-sfc.ts
98 lines (86 loc) · 3.17 KB
/
migrator-to-sfc.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
import path from 'path';
import { Project, SourceFile } from 'ts-morph';
import logger from './logger';
export const getScriptContent = (vueSourceFile: SourceFile): string | undefined => {
const scriptTagRegex = /<script[^>]*>([\s\S]*?)<\/script>/;
const match = vueSourceFile.getText().match(scriptTagRegex);
return match ? match[1] : undefined;
};
export const injectScript = (tsSourceFile: SourceFile, vueTemplate: string): string => {
const scriptTag = vueTemplate.match(/<script.*\/>|<script.*>([\s\S]*)<\/script>/);
if (!scriptTag) {
throw new Error('Script tag not foung on vue file.');
}
return vueTemplate.replace(
scriptTag[0],
`<script lang="ts">\n${tsSourceFile.getText()}\n</script>`,
);
};
const injectScss = (
scssSourceFile: SourceFile | undefined,
vueTemplate: string,
scoped: boolean,
): string => {
if (!scssSourceFile) {
return vueTemplate;
}
// Match the style tag.
const styleTag = vueTemplate.match(/<style.*\/>|<style.*>([\s\S]*)<\/style>/);
if (!styleTag) {
logger.warn(
`Style file found but style tag not present on vue file. The scss file will be deleted.: ${scssSourceFile.getFilePath()}`,
);
return vueTemplate;
}
return vueTemplate.replace(
styleTag[0],
`<style lang="scss"${scoped ? ' scoped' : ''}>\n${scssSourceFile.getText()}\n</style>`,
);
};
export const getScriptSrc = (vueSourceFile: SourceFile): string | undefined => {
// Regex that extracts the src from the <script> tag.
const scriptTagRegex = /<script[^>]+src=["']([^"']+)["'][^>]*>/;
const match = vueSourceFile.getText().match(scriptTagRegex);
return match ? match[1] : undefined;
};
export const getStyleSrc = (vueSourceFile: SourceFile): {
filePath: string;
scoped: boolean;
} | undefined => {
// Regex that extracts the src from the <style> tag.
const styleTagRegex = /<style[^>]+src=["']([^"']+)["'][^>]*>/;
const match = vueSourceFile.getText().match(styleTagRegex);
return match ? {
filePath: match[1],
scoped: match[0].includes(' scoped '),
} : undefined;
};
export const vueFileToSFC = async (
project: Project,
vueSourceFile: SourceFile,
): Promise<SourceFile> => {
let vueFileText = vueSourceFile.getText();
const tsFileRelativePath = getScriptSrc(vueSourceFile);
if (tsFileRelativePath) {
const tsFileAbsolutePath = path.resolve(vueSourceFile.getDirectoryPath(), tsFileRelativePath);
const tsSourceFile = project.addSourceFileAtPath(tsFileAbsolutePath);
vueFileText = injectScript(tsSourceFile, vueFileText);
await tsSourceFile.deleteImmediately();
}
const styleFileRelativePath = getStyleSrc(vueSourceFile);
if (styleFileRelativePath) {
const styleFileAbsolutePath = path.resolve(
vueSourceFile.getDirectoryPath(),
styleFileRelativePath.filePath,
);
const styleSourceFile = project.addSourceFileAtPath(styleFileAbsolutePath);
vueFileText = injectScss(styleSourceFile, vueFileText, styleFileRelativePath.scoped);
await styleSourceFile.deleteImmediately();
}
if (tsFileRelativePath || styleFileRelativePath) {
vueSourceFile.removeText();
vueSourceFile.insertText(0, vueFileText);
await vueSourceFile.save();
}
return vueSourceFile;
};