-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Should be able to parse to extract values template string (#77)
* fix: Should be able to parse to extract values template string * fix: updated unit test code * fix: updated unit test code
- Loading branch information
1 parent
6560cfb
commit 40f4077
Showing
13 changed files
with
2,285 additions
and
2,427 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
{ | ||
"extends": "@baiwusanyu", | ||
"rules": { | ||
"no-console": ["warn", { "allow": ["log"] }] | ||
"no-console": ["warn", { "allow": ["log"] }], | ||
"no-template-curly-in-string": "off" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
|
||
import { beforeEach, describe, expect, test } from 'vitest' | ||
import { parse } from '@babel/parser' | ||
import { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import { describe, expect, test } from 'vitest' | ||
import { parseCssVars } from '../parser-vbind-m' | ||
|
||
describe('analyze css vbind', () => { | ||
test('Should be able to parse to extract the v-bind-m value', () => { | ||
const source = ` | ||
.test { | ||
color: v-bind-m(color); | ||
} | ||
` | ||
const expected = ['color'] | ||
expect(parseCssVars([source])).toMatchObject(expected) | ||
}) | ||
|
||
test('Should be able to parse single quoted values', () => { | ||
const source = ` | ||
.test { | ||
color: v-bind-m('color'); | ||
} | ||
` | ||
const expected = ['color'] | ||
expect(parseCssVars([source])).toMatchObject(expected) | ||
}) | ||
|
||
test('Should be able to parse double quoted values', () => { | ||
const source = ` | ||
.test { | ||
color: v-bind-m("color"); | ||
} | ||
` | ||
const expected = ['color'] | ||
expect(parseCssVars([source])).toMatchObject(expected) | ||
}) | ||
|
||
test('Should be able to parse the value of the template string', () => { | ||
const source = ` | ||
.test { | ||
color: v-bind-m(\`\${v}\`); | ||
background-image: v-bind-m('\`url('\${bgUrl}')\`'); | ||
} | ||
` | ||
|
||
const expected = ['`${v}`', '`url(\'${bgUrl}\')`'] | ||
expect(parseCssVars([source])).toMatchObject(expected) | ||
}) | ||
|
||
test('Should be able to parse extract v-bind-m values in nested', () => { | ||
const source = ` | ||
.parent { | ||
.child { | ||
color: v-bind-m(color); | ||
} | ||
} | ||
` | ||
const expected = ['color'] | ||
expect(parseCssVars([source])).toMatchObject(expected) | ||
}) | ||
|
||
test('Should be able to parse extract v-bind-m values when ignoring single line comments', () => { | ||
const source = ` | ||
.test { | ||
color: v-bind-m(color); // this is a comment | ||
} | ||
` | ||
const expected = ['color'] | ||
expect(parseCssVars([source])).toMatchObject(expected) | ||
}) | ||
|
||
test('Should be able to parse extract v-bind-m values when ignoring multi-line comments', () => { | ||
const source = ` | ||
.test { | ||
color: v-bind-m(color); /* this is a | ||
multi-line | ||
comment */ | ||
} | ||
` | ||
const expected = ['color'] | ||
expect(parseCssVars([source])).toMatchObject(expected) | ||
}) | ||
|
||
test('Should be able to extract multiple v-bind-m values in analysis', () => { | ||
const source = ` | ||
.test { | ||
color: v-bind-m(color1); | ||
background-color: v-bind-m(color2); | ||
} | ||
` | ||
const expected = ['color1', 'color2'] | ||
expect(parseCssVars([source])).toMatchObject(expected) | ||
}) | ||
|
||
test('Should only analyze to extract unique values', () => { | ||
const source = ` | ||
.test { | ||
color: v-bind-m(color1); | ||
background-color: v-bind-m(color1); | ||
} | ||
` | ||
const expected = ['color1'] | ||
expect(parseCssVars([source])).toMatchObject(expected) | ||
}) | ||
|
||
test('Should be able to parse to extract values inside nested parentheses', () => { | ||
const source = ` | ||
.test { | ||
color: v-bind-m(((color1))); | ||
} | ||
` | ||
const expected = ['((color1))'] | ||
expect(parseCssVars([source])).toMatchObject(expected) | ||
}) | ||
|
||
test('Should be able to parse to extract values template string', () => { | ||
const source = '.test{ color: v-bind-m(`${v}`);\n background-image: v-bind-m("`url(\'${bgUrl}\')`");}' | ||
const expected = ['`${v}`', "`url('${bgUrl}')`"] | ||
expect(parseCssVars([source])).toMatchObject(expected) | ||
}) | ||
|
||
test('the right parenthesis is missing', () => { | ||
const source = ` | ||
.test { | ||
v-bind-m(color1; | ||
} | ||
` | ||
expect(parseCssVars([source])).toMatchObject([]) | ||
}) | ||
|
||
test('the left parenthesis is missing', () => { | ||
const source = ` | ||
.test { | ||
v-bind-m color1); | ||
} | ||
` | ||
expect(parseCssVars([source])).toMatchObject([]) | ||
}) | ||
|
||
test('should be able to parse incomplete expressions', () => { | ||
const source = ` | ||
.test { | ||
font-weight: v-bind-m("count.toString("); | ||
font-weight: v-bind-m(xxx); | ||
} | ||
` | ||
expect(parseCssVars([source])).toMatchObject(['count.toString(', 'xxx']) | ||
}) | ||
}) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
export * from './parser-variable' | ||
export * from './parser-import' | ||
export * from './parser-vbindm' | ||
export * from './parser-vbind-m' | ||
export { parserCompiledSfc } from './parser-compiled-sfc' | ||
export type { IParseSFCRes } from './parser-compiled-sfc' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/** | ||
* Implementation from vue | ||
* https://github.com/vuejs/core/blob/main/packages/compiler-sfc/src/style/cssVars.ts | ||
*/ | ||
const enum LexerState { | ||
inParens, | ||
inSingleQuoteString, | ||
inDoubleQuoteString, | ||
} | ||
|
||
function lexBinding(content: string, start: number): number | null { | ||
let state: LexerState = LexerState.inParens | ||
let parenDepth = 0 | ||
|
||
for (let i = start; i < content.length; i++) { | ||
const char = content.charAt(i) | ||
switch (state) { | ||
case LexerState.inParens: | ||
if (char === '\'') { | ||
state = LexerState.inSingleQuoteString | ||
} else if (char === '"') { | ||
state = LexerState.inDoubleQuoteString | ||
} else if (char === '(') { | ||
parenDepth++ | ||
} else if (char === ')') { | ||
if (parenDepth > 0) | ||
parenDepth-- | ||
else | ||
return i | ||
} | ||
break | ||
case LexerState.inSingleQuoteString: | ||
if (char === '\'') | ||
state = LexerState.inParens | ||
|
||
break | ||
case LexerState.inDoubleQuoteString: | ||
if (char === '"') | ||
state = LexerState.inParens | ||
|
||
break | ||
} | ||
} | ||
return null | ||
} | ||
|
||
function normalizeExpression(exp: string) { | ||
exp = exp.trim() | ||
if ( | ||
(exp[0] === '\'' && exp[exp.length - 1] === '\'') | ||
|| (exp[0] === '"' && exp[exp.length - 1] === '"') | ||
) | ||
return exp.slice(1, -1) | ||
|
||
return exp | ||
} | ||
|
||
const vBindRE = /v-bind-m\s*\(/g | ||
|
||
export function parseCssVars( | ||
styles: string[], | ||
hook?: { | ||
getIndex(start: number, end: number): void | ||
}, | ||
): string[] { | ||
const vars: string[] = [] | ||
styles.forEach((style) => { | ||
let match: RegExpExecArray | null = null | ||
// ignore v-bind() in comments /* ... */ | ||
const content = style.replace(/\/\*([\s\S]*?)\*\//g, '') | ||
|
||
while ((match = vBindRE.exec(content))) { | ||
const start = match.index + match[0].length | ||
const end = lexBinding(content, start) | ||
if (end !== null) { | ||
hook && hook.getIndex(start, end) | ||
const variable = normalizeExpression(content.slice(start, end)) | ||
if (!vars.includes(variable)) | ||
vars.push(variable) | ||
} | ||
} | ||
}) | ||
return vars | ||
} |
Oops, something went wrong.