|
1 |
| -import type { BuiltInParserName } from "prettier"; |
2 |
| -import { zlibSync, unzlibSync, strToU8, strFromU8 } from "fflate"; |
3 |
| - |
4 |
| -const scriptRe = /<script[^>]*>([\s\S]*)<\/script>/; |
5 |
| -const exportDefaultRe = /export\s*default\s*\{([\s\S]*)\}\;?\s*<\/script>/; |
6 |
| -const setupRe = /setup\s*\(\)\s*\{([\s\S]*)return\s*\{([\s\S]*)\}\;?\s*\}\;?/; |
7 |
| -const layerRe = |
8 |
| - /import\s?\{\s?layer\s?\}\s?from\s?[\"|\']\@layui\/layer-vue[\"|\']/; |
9 |
| - |
10 |
| -// danger: 以下字符串拼接代码不可改动缩进或换行,否则会影响 URI hash 解码后代码的排版 |
11 | 1 | const MAIN_FILE_NAME = "App.vue";
|
12 | 2 |
|
13 |
| -/** |
14 |
| - * 将代码编码为 URI hash, 生成 playground 链接 |
15 |
| - * @param source 源码 |
16 |
| - * @param convertSetupSugar 转换 setup,仅字符串替换,没有做任何语法分析 |
17 |
| - * @returns 处理后的代码,URI hsah, playground 链接 |
18 |
| - } |
19 |
| - */ |
20 |
| -export const openPlayground = async ( |
21 |
| - source: string, |
22 |
| - convertSetupSugar: boolean |
23 |
| -) => { |
24 |
| - const decodeCode = source; |
25 |
| - const scriptResult = decodeCode.match(scriptRe); |
26 |
| - |
27 |
| - // 替换 script 标签 |
28 |
| - let code: string | undefined = decodeCode; |
29 |
| - if (convertSetupSugar) { |
30 |
| - if (scriptResult) { |
31 |
| - code = decodeCode.replace( |
32 |
| - scriptRe, |
33 |
| - `<script lang="ts" setup>$1 |
34 |
| - </script>` |
35 |
| - ); |
36 |
| - } else { |
37 |
| - code = `${decodeCode} |
38 |
| - <script lang="ts" setup> |
39 |
| -
|
40 |
| - </script>`; |
41 |
| - } |
42 |
| - |
43 |
| - // 去除 export default,保留其中的内容 |
44 |
| - const exportDefaultResult = code.match(exportDefaultRe); |
45 |
| - if (exportDefaultResult) { |
46 |
| - code = code.replace( |
47 |
| - exportDefaultRe, |
48 |
| - trimBr(exportDefaultResult[1] + `</script>`).trim() |
49 |
| - ); |
50 |
| - // console.log("export",code); |
51 |
| - } |
52 |
| - // 去除 setup 函数,保留其中的内容 |
53 |
| - const setupResult = code.match(setupRe); |
54 |
| - if (setupResult) { |
55 |
| - code = code.replace(setupRe, trimBr(setupResult[1])); |
56 |
| - // console.log("setup",code); |
57 |
| - } |
58 |
| - } |
59 |
| - // 替换 layer 引入语句 |
60 |
| - // playground 中使用最新版 layer 请从 @layui/layer-vue 引入 |
61 |
| - if (code.match(layerRe)) { |
62 |
| - code = code.replace(layerRe, `import { layer } from "@layui/layui-vue"`); |
63 |
| - // console.log("layer",code); |
64 |
| - } |
| 3 | +function utoa(data: string): string { |
| 4 | + return btoa(unescape(encodeURIComponent(data))); |
| 5 | +} |
65 | 6 |
|
66 |
| - code = await formatCode(MAIN_FILE_NAME, code); |
| 7 | +export const openPlayground = (source: string) => { |
| 8 | + const code = decodeURIComponent(source); |
67 | 9 | const originCode = {
|
68 | 10 | [MAIN_FILE_NAME]: code,
|
69 | 11 | };
|
70 | 12 |
|
71 | 13 | const encoded = utoa(JSON.stringify(originCode));
|
72 |
| - const link = `https://layui-vue.gitee.io/sandbox-vue/#${encoded}`; |
| 14 | + const link = `https://layui-vue.github.io/layui-vue-playground/#${encoded}`; |
73 | 15 | return {
|
74 |
| - code, |
75 | 16 | encoded,
|
76 | 17 | link,
|
77 | 18 | };
|
78 | 19 | };
|
79 |
| - |
80 |
| -/** |
81 |
| - * |
82 |
| - * @returns 格式化代码 |
83 |
| - */ |
84 |
| -async function formatCode(filename: string, data: string) { |
85 |
| - const [format, parserHtml, parserTypeScript, parserBabel, parserPostcss] = |
86 |
| - await Promise.all([ |
87 |
| - import("prettier/standalone").then((r) => r.format), |
88 |
| - import("prettier/parser-html").then((m) => m.default), |
89 |
| - import("prettier/parser-typescript").then((m) => m.default), |
90 |
| - import("prettier/parser-babel").then((m) => m.default), |
91 |
| - import("prettier/parser-postcss").then((m) => m.default), |
92 |
| - ]); |
93 |
| - let code = data; |
94 |
| - let parser: BuiltInParserName; |
95 |
| - if (filename.endsWith(".vue")) { |
96 |
| - parser = "vue"; |
97 |
| - } else if (filename.endsWith(".js")) { |
98 |
| - parser = "babel"; |
99 |
| - } else if (filename.endsWith(".ts")) { |
100 |
| - parser = "typescript"; |
101 |
| - } else if (filename.endsWith(".json")) { |
102 |
| - parser = "json"; |
103 |
| - } else { |
104 |
| - return; |
105 |
| - } |
106 |
| - code = format(code, { |
107 |
| - parser, |
108 |
| - plugins: [parserHtml, parserTypeScript, parserBabel, parserPostcss], |
109 |
| - semi: false, // 语句末尾打印分号 |
110 |
| - singleQuote: true, // 使用单引号 |
111 |
| - vueIndentScriptAndStyle: false, // 是否缩进 Vue 文件中的 script 和 style 标签 |
112 |
| - }); |
113 |
| - |
114 |
| - return code; |
115 |
| -} |
116 |
| - |
117 |
| -/** |
118 |
| - * 去除字符串两端的空白行 |
119 |
| - * @param str |
120 |
| - * @returns |
121 |
| - */ |
122 |
| -function trimBr(str: string): string { |
123 |
| - return str.replace(/(^[\r\n]*)|([\r\n]*$)/, ""); |
124 |
| -} |
125 |
| - |
126 |
| -export function utoa(data: string): string { |
127 |
| - const buffer = strToU8(data); |
128 |
| - const zipped = zlibSync(buffer, { level: 9 }); |
129 |
| - const binary = strFromU8(zipped, true); |
130 |
| - return btoa(binary); |
131 |
| -} |
132 |
| - |
133 |
| -export function atou(base64: string): string { |
134 |
| - const binary = atob(base64); |
135 |
| - |
136 |
| - // zlib header (x78), level 9 (xDA) |
137 |
| - if (binary.startsWith("\x78\xDA")) { |
138 |
| - const buffer = strToU8(binary, true); |
139 |
| - const unzipped = unzlibSync(buffer); |
140 |
| - return strFromU8(unzipped); |
141 |
| - } |
142 |
| - |
143 |
| - // old unicode hacks for backward compatibility |
144 |
| - // https://base64.guru/developers/javascript/examples/unicode-strings |
145 |
| - return decodeURIComponent(escape(binary)); |
146 |
| -} |
0 commit comments