From bcc0bb879bf38d4267cbbf5c35242f340d8f6e4a Mon Sep 17 00:00:00 2001 From: zjxxxxxxxxx <954270063@qq.com> Date: Sat, 23 Sep 2023 14:01:39 +0800 Subject: [PATCH] fix: jsx column is 1 less --- src/core/constants.ts | 11 +++-------- src/core/index.ts | 40 ++++++++++++--------------------------- src/core/transform.ts | 34 +++++++++++++++++++++++++++++++++ src/core/transform_JSX.ts | 22 +++++++++++---------- src/core/transform_SFC.ts | 13 +++++-------- tsup.config.ts | 2 +- 6 files changed, 67 insertions(+), 55 deletions(-) create mode 100644 src/core/transform.ts diff --git a/src/core/constants.ts b/src/core/constants.ts index 2c90e71..42c3e60 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -4,12 +4,7 @@ export const NodeTypes = { ELEMENT: 1, }; -export const ElementTypes = { - ELEMENT: 0, - COMPONENT: 1, -}; - -export const TagTypes = [ - ElementTypes.ELEMENT, - ElementTypes.COMPONENT, +export const TagTypes = [ + 0, // ELEMENT + 1, // COMPONENT ]; diff --git a/src/core/index.ts b/src/core/index.ts index a783175..9ed92fc 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -1,13 +1,8 @@ -import type { Position } from '@vue/compiler-dom'; import type { UnpluginFactory } from 'unplugin'; import { createUnplugin } from 'unplugin'; -import MagicString from 'magic-string'; import type { Options } from '../types'; -import { TRACE_ID } from './constants'; import { filter_ID } from './filter_ID'; -import { parse_ID } from './parse_ID'; -import { transform_SFC } from './transform_SFC'; -import { transform_JSX } from './transform_JSX'; +import { transform } from './transform'; export const unpluginFactory: UnpluginFactory = (options = {}) => { if (process.env.NODE_ENV !== 'development') { @@ -16,36 +11,25 @@ export const unpluginFactory: UnpluginFactory = (options = {}) => { }; } - const { root = process.cwd(), sourceMap = false } = options; + const opts = resolveOptions(options); return { name: 'unplugin-vue-source', enforce: 'pre', transformInclude: filter_ID, transform(code, id) { - const s = new MagicString(code); - - const parsed = parse_ID(id, root); - if (parsed.isSfc) { - transform_SFC(code, replace); - } else if (parsed.isJsx) { - transform_JSX(code, replace, parsed); - } - - function replace(pos: Position) { - const { offset, line, column } = pos; - s.prependLeft( - offset, - ` ${TRACE_ID}="${parsed.file}:${line}:${column}"`, - ); - } - - return { - code: s.toString(), - map: sourceMap ? s.generateMap() : null, - }; + return transform(code, id, opts); }, }; }; +function resolveOptions(options: Options): Required { + const { root = process.cwd(), sourceMap = false } = options; + + return { + root, + sourceMap, + }; +} + export default /* #__PURE__ */ createUnplugin(unpluginFactory); diff --git a/src/core/transform.ts b/src/core/transform.ts new file mode 100644 index 0000000..dc5c38b --- /dev/null +++ b/src/core/transform.ts @@ -0,0 +1,34 @@ +import type { Position } from '@vue/compiler-dom'; +import MagicString from 'magic-string'; +import type { Options } from '../types'; +import { TRACE_ID } from './constants'; +import { parse_ID } from './parse_ID'; +import { transform_SFC } from './transform_SFC'; +import { transform_JSX } from './transform_JSX'; + +export function transform( + code: string, + id: string, + options: Required, +) { + const { root, sourceMap } = options; + + const s = new MagicString(code); + + const parsed = parse_ID(id, root); + if (parsed.isSfc) { + transform_SFC(code, replace); + } else if (parsed.isJsx) { + transform_JSX(code, replace, parsed); + } + + function replace(pos: Position) { + const { offset, line, column } = pos; + s.prependLeft(offset, ` ${TRACE_ID}="${parsed.file}:${line}:${column}"`); + } + + return { + code: s.toString(), + map: sourceMap ? s.generateMap() : null, + }; +} diff --git a/src/core/transform_JSX.ts b/src/core/transform_JSX.ts index 4d8a720..a5d03dc 100644 --- a/src/core/transform_JSX.ts +++ b/src/core/transform_JSX.ts @@ -4,7 +4,7 @@ import { parse, ParserPlugin } from '@babel/parser'; export function transform_JSX( code: string, - transformer: (pos: Position) => void, + cb: (pos: Position) => void, options: { isTsx?: boolean; startIndex?: number; @@ -12,7 +12,7 @@ export function transform_JSX( startColumn?: number; }, ) { - const { isTsx, startIndex = 0, startLine = 1, startColumn = 0 } = options; + const { isTsx, startIndex = 0, startLine = 1, startColumn = 1 } = options; const plugins: ParserPlugin[] = ['jsx']; if (isTsx) { @@ -23,21 +23,23 @@ export function transform_JSX( sourceType: 'unambiguous', plugins, startLine, - startColumn, - })!; + // babel start at 0 + startColumn: startColumn - 1, + }); traverse(ast, { JSXOpeningElement({ node }) { const nameNode = node.name; - if (!nameNode) { - // <> return - return; - } + // <> return + if (!nameNode) return; const { start } = node.loc!; const name = getJSXElementName(nameNode); - transformer({ + const offset = start.index + startIndex + name.length + 1; + cb({ ...start, - offset: start.index + startIndex + name.length + 1, + // babel starts at 0, so we need to add 1 + column: start.column + 1, + offset, }); }, }); diff --git a/src/core/transform_SFC.ts b/src/core/transform_SFC.ts index 56a05d4..f9fdbd5 100644 --- a/src/core/transform_SFC.ts +++ b/src/core/transform_SFC.ts @@ -9,10 +9,7 @@ import { parse, transform } from '@vue/compiler-dom'; import { NodeTypes, TagTypes } from './constants'; import { transform_JSX } from './transform_JSX'; -export function transform_SFC( - code: string, - transformer: (pos: Position) => void, -) { +export function transform_SFC(code: string, cb: (pos: Position) => void) { const ast = parse(code); transform(ast, { nodeTransforms: [ @@ -22,10 +19,10 @@ export function transform_SFC( TagTypes.includes(node.tagType) ) { const { start } = node.loc; - - transformer({ + const offset = start.offset + node.tag.length + 1; + cb({ ...start, - offset: start.offset + node.tag.length + 1, + offset, }); } }, @@ -34,7 +31,7 @@ export function transform_SFC( const jsxOpts = resolveJsxOptions(ast); if (jsxOpts) { - transform_JSX(jsxOpts.code, transformer, jsxOpts); + transform_JSX(jsxOpts.code, cb, jsxOpts); } } diff --git a/tsup.config.ts b/tsup.config.ts index 8aa9e66..6f26702 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -9,10 +9,10 @@ export const tsup: Options = { shims: false, cjsInterop: true, external: [ - '@vue/compiler-dom', '@babel/core', '@babel/parser', '@babel/plugin-syntax-jsx', '@babel/plugin-syntax-typescript', + '@vue/compiler-dom', ], };