Skip to content
This repository was archived by the owner on Dec 25, 2024. It is now read-only.

Commit b6783aa

Browse files
committed
feat: support pug
1 parent 56706e0 commit b6783aa

File tree

5 files changed

+145
-68
lines changed

5 files changed

+145
-68
lines changed

package.json

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,67 +2,80 @@
22
"name": "unplugin-vue2-script-setup",
33
"version": "0.5.8",
44
"description": "Bring <script setup> to Vue 2",
5-
"main": "dist/index.js",
6-
"module": "dist/index.mjs",
7-
"types": "index.d.ts",
5+
"keywords": [],
6+
"homepage": "https://github.com/antfu/unplugin-vue2-script-setup#readme",
7+
"bugs": {
8+
"url": "https://github.com/antfu/unplugin-vue2-script-setup/issues"
9+
},
10+
"repository": {
11+
"type": "git",
12+
"url": "git+https://github.com/antfu/unplugin-vue2-script-setup.git"
13+
},
14+
"funding": "https://github.com/sponsors/antfu",
15+
"license": "MIT",
16+
"author": "Anthony Fu <[email protected]>",
817
"exports": {
918
".": {
1019
"require": "./dist/index.js",
1120
"import": "./dist/index.mjs"
1221
},
13-
"./vite": {
14-
"require": "./dist/vite.js",
15-
"import": "./dist/vite.mjs"
16-
},
17-
"./webpack": {
18-
"require": "./dist/webpack.js",
19-
"import": "./dist/webpack.mjs"
20-
},
21-
"./rollup": {
22-
"require": "./dist/rollup.js",
23-
"import": "./dist/rollup.mjs"
22+
"./*": "./*",
23+
"./jest": {
24+
"require": "./jest.js"
2425
},
2526
"./nuxt": {
2627
"require": "./dist/nuxt.js",
2728
"import": "./dist/nuxt.mjs"
2829
},
29-
"./jest": {
30-
"require": "./jest.js"
30+
"./rollup": {
31+
"require": "./dist/rollup.js",
32+
"import": "./dist/rollup.mjs"
3133
},
3234
"./types": {
3335
"require": "./dist/types.js",
3436
"import": "./dist/types.mjs"
3537
},
36-
"./*": "./*"
37-
},
38-
"funding": "https://github.com/sponsors/antfu",
39-
"author": "Anthony Fu <[email protected]>",
40-
"license": "MIT",
41-
"bugs": {
42-
"url": "https://github.com/antfu/unplugin-vue2-script-setup/issues"
43-
},
44-
"homepage": "https://github.com/antfu/unplugin-vue2-script-setup#readme",
45-
"repository": {
46-
"type": "git",
47-
"url": "git+https://github.com/antfu/unplugin-vue2-script-setup.git"
38+
"./vite": {
39+
"require": "./dist/vite.js",
40+
"import": "./dist/vite.mjs"
41+
},
42+
"./webpack": {
43+
"require": "./dist/webpack.js",
44+
"import": "./dist/webpack.mjs"
45+
}
4846
},
49-
"keywords": [],
47+
"main": "dist/index.js",
48+
"module": "dist/index.mjs",
49+
"types": "index.d.ts",
5050
"files": [
5151
"dist",
5252
"jest.js",
5353
"*.d.ts"
5454
],
5555
"scripts": {
56-
"prepublishOnly": "nr build",
5756
"build": "rimraf dist && tsup 'src/*.ts' --format cjs,esm --dts && esno scripts/postbuild.ts",
5857
"dev": "tsup 'src/*.ts' --watch src",
59-
"play": "npm -C playground run dev",
60-
"release": "bumpp --commit --push --tag && pnpm publish",
6158
"lint": "eslint \"{src,test}/**/*.ts\"",
6259
"lint:fix": "nr lint -- --fix",
60+
"play": "npm -C playground run dev",
61+
"prepublishOnly": "nr build",
62+
"release": "bumpp --commit --push --tag && pnpm publish",
6363
"test": "jest",
6464
"test:update": "jest -u"
6565
},
66+
"dependencies": {
67+
"@babel/core": "^7.15.0",
68+
"@babel/generator": "^7.15.0",
69+
"@babel/parser": "^7.15.3",
70+
"@babel/traverse": "^7.15.0",
71+
"@babel/types": "^7.15.0",
72+
"@vue/ref-transform": "^3.2.6",
73+
"@vue/shared": "^3.2.6",
74+
"defu": "^5.0.0",
75+
"htmlparser2": "^6.1.0",
76+
"magic-string": "^0.25.7",
77+
"unplugin": "^0.2.7"
78+
},
6679
"devDependencies": {
6780
"@antfu/eslint-config": "^0.7.0",
6881
"@antfu/ni": "^0.7.0",
@@ -79,23 +92,14 @@
7992
"fast-glob": "^3.2.7",
8093
"jest": "^27.1.0",
8194
"log-editor": "^0.1.0",
95+
"pug": "^3.0.2",
8296
"rimraf": "^3.0.2",
8397
"ts-jest": "^27.0.5",
8498
"tsup": "^4.14.0",
8599
"typescript": "^4.4.2",
86100
"vite": "^2.5.3"
87101
},
88-
"dependencies": {
89-
"@babel/core": "^7.15.0",
90-
"@babel/generator": "^7.15.0",
91-
"@babel/parser": "^7.15.3",
92-
"@babel/traverse": "^7.15.0",
93-
"@babel/types": "^7.15.0",
94-
"@vue/ref-transform": "^3.2.6",
95-
"@vue/shared": "^3.2.6",
96-
"defu": "^5.0.0",
97-
"htmlparser2": "^6.1.0",
98-
"magic-string": "^0.25.7",
99-
"unplugin": "^0.2.7"
102+
"optionalDependencies": {
103+
"pug": "^3.0.0"
100104
}
101105
}

pnpm-lock.yaml

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/core/parseSFC.ts

Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Parser as HTMLParser } from 'htmlparser2'
1+
import { Parser as HTMLParser, ParserOptions as HTMLParserOptions } from 'htmlparser2'
22
import { parse, ParserOptions } from '@babel/parser'
33
import { camelize, capitalize, isHTMLTag, isSVGTag, isVoidTag } from '@vue/shared'
44
import { ParsedSFC, ScriptSetupTransformOptions, ScriptTagMeta } from '../types'
@@ -33,31 +33,63 @@ export function parseSFC(code: string, id?: string, options?: ScriptSetupTransfo
3333
found: false,
3434
ast: undefined!,
3535
}
36+
const htmlParserOptions: HTMLParserOptions = {
37+
xmlMode: true,
38+
lowerCaseTags: false,
39+
lowerCaseAttributeNames: false,
40+
recognizeSelfClosing: true,
41+
}
42+
43+
let pugStart: number | undefined
44+
45+
function handleTemplateContent(name: string, attributes: Record<string, string>) {
46+
if (!isHTMLTag(name) && !isSVGTag(name) && !isVoidTag(name))
47+
components.add(capitalize(camelize(name)))
48+
49+
Object.entries(attributes).forEach(([key, value]) => {
50+
if (!value)
51+
return
52+
if (key.startsWith('v-') || key.startsWith('@') || key.startsWith(':')) {
53+
if (key === 'v-for')
54+
// we strip out delectations for v-for before `in` or `of`
55+
expressions.add(`(${value.replace(/^.*\s(?:in|of)\s/, '')})`)
56+
else
57+
expressions.add(`(${value})`)
58+
}
59+
if (key === 'ref')
60+
identifiers.add(value)
61+
})
62+
}
63+
64+
function handlePugTemplate(pugCode: string, id?: string) {
65+
try {
66+
// eslint-disable-next-line @typescript-eslint/no-var-requires
67+
const html = require('pug').compile(pugCode, { filename: id })()
68+
const parser = new HTMLParser({
69+
onopentag(name, attributes) {
70+
name && handleTemplateContent(name, attributes)
71+
},
72+
}, htmlParserOptions)
73+
74+
parser.write(html)
75+
parser.end()
76+
}
77+
catch {}
78+
}
3679

3780
const parser = new HTMLParser({
3881
onopentag(name, attributes) {
3982
if (!name)
4083
return
4184

42-
if (name === 'template')
85+
if (name === 'template') {
86+
if (templateLevel === 0 && attributes.lang === 'pug')
87+
pugStart = parser.endIndex! + 1
4388
templateLevel += 1
89+
}
4490

4591
if (templateLevel > 0) {
46-
if (!isHTMLTag(name) && !isSVGTag(name) && !isVoidTag(name))
47-
components.add(capitalize(camelize(name)))
48-
Object.entries(attributes).forEach(([key, value]) => {
49-
if (!value)
50-
return
51-
if (key.startsWith('v-') || key.startsWith('@') || key.startsWith(':')) {
52-
if (key === 'v-for')
53-
// we strip out delectations for v-for before `in` or `of`
54-
expressions.add(`(${value.replace(/^.*\s(?:in|of)\s/, '')})`)
55-
else
56-
expressions.add(`(${value})`)
57-
}
58-
if (key === 'ref')
59-
identifiers.add(value)
60-
})
92+
handleTemplateContent(name, attributes)
6193
}
6294
else {
6395
if (name === 'script') {
@@ -86,8 +118,11 @@ export function parseSFC(code: string, id?: string, options?: ScriptSetupTransfo
86118
}
87119
},
88120
onclosetag(name) {
89-
if (name === 'template')
121+
if (name === 'template') {
90122
templateLevel -= 1
123+
if (templateLevel === 0 && pugStart != null)
124+
handlePugTemplate(code.slice(pugStart, parser.startIndex), id)
125+
}
91126

92127
if (inScriptSetup && name === 'script') {
93128
scriptSetup.end = parser.endIndex! + 1
@@ -102,12 +137,7 @@ export function parseSFC(code: string, id?: string, options?: ScriptSetupTransfo
102137
inScript = false
103138
}
104139
},
105-
}, {
106-
xmlMode: true,
107-
lowerCaseTags: false,
108-
lowerCaseAttributeNames: false,
109-
recognizeSelfClosing: true,
110-
})
140+
}, htmlParserOptions)
111141

112142
parser.write(code)
113143
parser.end()

test/__snapshots__/transform.test.ts.snap

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,34 @@ export default __sfc_main;
400400
"
401401
`;
402402
403+
exports[`transform fixtures test/fixtures/Pug1.vue 1`] = `
404+
"<template lang=\\"pug\\">
405+
.root
406+
span {{ data }} {{ title }}
407+
.p-1(@click=\\"foo\\")
408+
</template>
409+
410+
<script lang=\\"ts\\">
411+
const __sfc_main = {};
412+
413+
__sfc_main.setup = (__props, __ctx) => {
414+
const data = {
415+
title: 'Template Only'
416+
};
417+
418+
function foo() {}
419+
420+
return {
421+
data,
422+
foo
423+
};
424+
};
425+
426+
export default __sfc_main;
427+
</script>
428+
"
429+
`;
430+
403431
exports[`transform fixtures test/fixtures/RefSugar.ts 1`] = `
404432
"import { ref as _ref, computed as _computed } from '@vue/composition-api'
405433
/* eslint-disable @typescript-eslint/no-unused-vars */

test/fixtures/Pug1.vue

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<template lang="pug">
2+
.root
3+
span {{ data }} {{ title }}
4+
.p-1(@click="foo")
5+
</template>
6+
7+
<script setup lang="ts">
8+
const data = {
9+
title: 'Template Only',
10+
}
11+
12+
function foo() {}
13+
</script>

0 commit comments

Comments
 (0)