Skip to content

Commit

Permalink
feat: source map support for transformers (#665)
Browse files Browse the repository at this point in the history
* feat: source map support for transform directives

* chore: remove unused options

* refactor

* fix: remove last return

Co-authored-by: Saya <chu121su12@gmail.com>
  • Loading branch information
hannoeru and chu121su12 committed Mar 1, 2022
1 parent 0e1bdf8 commit 9ddd2e8
Show file tree
Hide file tree
Showing 20 changed files with 248 additions and 161 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ coverage
.output
.nuxt
!.vitepress
__snapshots__
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"fs-extra": "^10.0.0",
"gzip-size": "^6.0.0",
"lz-string": "^1.4.4",
"magic-string": "^0.25.7",
"prettier": "^2.5.1",
"rollup": "^2.68.0",
"semver": "^7.3.5",
Expand Down
1 change: 1 addition & 0 deletions packages/core/build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default defineBuildConfig({
declaration: true,
externals: [
'unconfig',
'magic-string',
],
rollup: {
emitCJS: true,
Expand Down
4 changes: 4 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,9 @@
"scripts": {
"build": "unbuild",
"stub": "unbuild --stub"
},
"devDependencies": {
"magic-string": "^0.25.7",
"unconfig": "^0.3.1"
}
}
3 changes: 2 additions & 1 deletion packages/core/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { LoadConfigResult } from 'unconfig'
import type MagicString from 'magic-string'
import type { UnoGenerator } from './generator'
import type { BetterMap } from './utils'

Expand Down Expand Up @@ -377,7 +378,7 @@ export interface SourceCodeTransformer {
/**
* The transform function
*/
transform: (code: string, id: string, ctx: UnocssPluginContext) => Awaitable<string | TransformResult | null | undefined>
transform: (code: MagicString, id: string, ctx: UnocssPluginContext) => Awaitable<void>
}

/**
Expand Down
3 changes: 3 additions & 0 deletions packages/transformer-directives/build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export default defineBuildConfig({
],
clean: true,
declaration: true,
externals: [
'magic-string',
],
rollup: {
emitCJS: true,
},
Expand Down
3 changes: 3 additions & 0 deletions packages/transformer-directives/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,8 @@
"dependencies": {
"@unocss/core": "workspace:*",
"css-tree": "^2.0.4"
},
"devDependencies": {
"magic-string": "^0.25.7"
}
}
51 changes: 16 additions & 35 deletions packages/transformer-directives/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { expandVariantGroup, notNull, regexScopePlaceholder } from '@unocss/core'
import type { SourceCodeTransformer, StringifiedUtil, UnoGenerator } from '@unocss/core'
import type { CssNode, ListItem, Selector, SelectorList, StyleSheet } from 'css-tree'
import { List, clone, generate, parse, walk } from 'css-tree'
import type { CssNode, List, ListItem, Selector, SelectorList } from 'css-tree'
import { clone, generate, parse, walk } from 'css-tree'
import type MagicString from 'magic-string'
import { regexCssId } from '../../plugins-common/defaults'

type Writeable<T> = { -readonly [P in keyof T]: T[P] }
Expand All @@ -17,27 +18,27 @@ export default function transformerDirectives(): SourceCodeTransformer {
}
}

export async function transformDirectives(css: string, uno: UnoGenerator, filename?: string) {
if (!css.includes('@apply'))
return css
export async function transformDirectives(code: MagicString, uno: UnoGenerator, filename?: string) {
if (!code.original.includes('@apply'))
return

const ast = parse(css, {
const ast = parse(code.original, {
parseAtrulePrelude: false,
positions: true,
filename,
})

if (ast.type !== 'StyleSheet')
return css
return

const stack: Promise<void>[] = []

const processNode = async(node: CssNode, item: ListItem<CssNode>, list: List<CssNode>) => {
const processNode = async(node: CssNode, _item: ListItem<CssNode>, _list: List<CssNode>) => {
if (node.type !== 'Rule')
return

await Promise.all(
node.block.children.map(async(childNode, childItem) => {
node.block.children.map(async(childNode, _childItem) => {
if (!(childNode.type === 'Atrule' && childNode.name === 'apply' && childNode.prelude))
return

Expand Down Expand Up @@ -73,14 +74,12 @@ export async function transformDirectives(css: string, uno: UnoGenerator, filena

if (parent) {
const newNodeCss = `${parent}{${parentSelector}{${body}}}`
const insertNodeAst = parse(newNodeCss) as StyleSheet
list.insertList(insertNodeAst.children, item)
code.appendLeft(node.loc!.start.offset, newNodeCss)
}
else if (selector && selector !== '.\\-') {
const selectorAST = parse(selector, {
context: 'selector',
}) as Selector
// console.log({ selectorAST: selectorAST.children.toArray() })

const prelude = clone(node.prelude) as SelectorList

Expand All @@ -94,41 +93,23 @@ export async function transformDirectives(css: string, uno: UnoGenerator, filena
})

const newNodeCss = `${generate(prelude)}{${body}}`
const insertNodeAst = parse(newNodeCss) as StyleSheet

list.insertList(insertNodeAst.children, item)
code.appendLeft(node.loc!.start.offset, newNodeCss)
}
else if (node.block.children.toArray().length === 1) {
const newNodeCss = `${parentSelector}{${body}}`
const insertNodeAst = parse(newNodeCss) as StyleSheet
list.insertList(insertNodeAst.children, item)
code.appendLeft(node.loc!.start.offset, newNodeCss)
code.remove(node.loc!.start.offset, node.loc!.end.offset)
}
else {
const rules = new List<string>()
.fromArray(body
.replace(/;$/, '')
.split(';'),
).map(i => parse(i, {
context: 'declaration',
}))

node.block.children.insertList(rules, childItem)
code.appendRight(childNode.loc!.end.offset, body)
}
}
node.block.children.remove(childItem)
code.remove(childNode.loc!.start.offset, childNode.loc!.end.offset)
}).toArray(),
)
}

walk(ast, (...args) => stack.push(processNode(...args)))

await Promise.all(stack)

ast.children = ast.children.filter((cssNode) => {
if ('block' in cssNode)
return (cssNode.block?.children.toArray().length ?? 1) !== 0
return true
})

return generate(ast)
}
3 changes: 3 additions & 0 deletions packages/transformer-variant-group/build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export default defineBuildConfig({
],
clean: true,
declaration: true,
externals: [
'magic-string',
],
rollup: {
emitCJS: true,
},
Expand Down
4 changes: 3 additions & 1 deletion packages/transformer-variant-group/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@
"stub": "unbuild --stub"
},
"dependencies": {
"@unocss/core": "workspace:*",
"@unocss/core": "workspace:*"
},
"devDependencies": {
"magic-string": "^0.25.7"
}
}
21 changes: 4 additions & 17 deletions packages/transformer-variant-group/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { SourceCodeTransformer } from '@unocss/core'
import { regexClassGroup } from '@unocss/core'
import MagicString from 'magic-string'
import type MagicString from 'magic-string'

export default function transformerVariantGroup(): SourceCodeTransformer {
return {
Expand All @@ -12,29 +12,16 @@ export default function transformerVariantGroup(): SourceCodeTransformer {
}
}

export function transformVariantGroups(code: string, sourcemap = true) {
const s = new MagicString(code)
let hasReplaced = false
export function transformVariantGroups(code: MagicString) {
let match

regexClassGroup.lastIndex = 0
// eslint-disable-next-line no-cond-assign
while ((match = regexClassGroup.exec(code))) {
hasReplaced = true
while ((match = regexClassGroup.exec(code.original))) {
const start = match.index
const end = start + match[0].length
const [, pre, sep, body] = match
const replacement = body.split(/\s/g).map(i => i.replace(/^(!?)(.*)/, `$1${pre}${sep}$2`)).join(' ')
s.overwrite(start, end, replacement)
}

if (!hasReplaced)
return null

return {
code: s.toString(),
map: sourcemap
? s.generateMap({ hires: true })
: undefined,
code.overwrite(start, end, replacement)
}
}
3 changes: 2 additions & 1 deletion packages/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
"@unocss/core": "workspace:*",
"@unocss/inspector": "workspace:*",
"@unocss/scope": "workspace:*",
"@unocss/transformer-directives": "workspace:*"
"@unocss/transformer-directives": "workspace:*",
"magic-string": "^0.25.7"
},
"devDependencies": {
"vite": "^2.8.4"
Expand Down
34 changes: 12 additions & 22 deletions packages/vite/src/transformers.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { TransformPluginContext } from 'rollup'
import type { Plugin } from 'vite'
import type { UnocssPluginContext } from '@unocss/core'
import MagicString from 'magic-string'

export function initTransformerPlugins(ctx: UnocssPluginContext): Plugin[] {
async function applyTransformers(c: TransformPluginContext, _code: string, id: string, enforce?: 'pre' | 'post') {
async function applyTransformers(code: string, id: string, enforce?: 'pre' | 'post') {
const transformers = (ctx.uno.config.transformers || []).filter(i => i.enforce === enforce)
if (!transformers.length)
return undefined
return

let code = _code
const s = new MagicString(code)
for (const t of transformers) {
if (t.idFilter) {
if (!t.idFilter(id))
Expand All @@ -17,43 +17,33 @@ export function initTransformerPlugins(ctx: UnocssPluginContext): Plugin[] {
else if (!ctx.filter(code, id)) {
continue
}
const result = (await t.transform(code, id, ctx))
if (result == null)
continue
if (typeof result === 'string') {
code = result
}
else {
code = result.code
if (result.map && 'sourcemapChain' in c)
// @ts-expect-error unexposed types
c.sourcemapChain.push(result.map)
}
await t.transform(s, id, ctx)
}
return {
code: s.toString(),
map: s.generateMap({ hires: true }),
}
if (code === _code)
return null
return code
}

return [
{
name: 'unocss:transformers:default',
transform(code, id) {
return applyTransformers(this, code, id)
return applyTransformers(code, id)
},
},
{
name: 'unocss:transformers:pre',
enforce: 'pre',
transform(code, id) {
return applyTransformers(this, code, id, 'pre')
return applyTransformers(code, id, 'pre')
},
},
{
name: 'unocss:transformers:post',
enforce: 'post',
transform(code, id) {
return applyTransformers(this, code, id, 'post')
return applyTransformers(code, id, 'post')
},
},
]
Expand Down
11 changes: 5 additions & 6 deletions playground/src/components/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -110,18 +110,14 @@ onMounted(() => {
</div>
<a
i-carbon-logo-github
text-xl
op75
hover:op100
class="icon-btn"
href="https://github.com/unocss/unocss"
target="_blank"
/>
<button
i-carbon-sun
dark-i-carbon-moon
text-xl
op75
hover:op100
class="icon-btn"
@click="isDark = !isDark"
/>
</TitleBar>
Expand Down Expand Up @@ -187,4 +183,7 @@ onMounted(() => {
.splitpanes.loading .splitpanes__pane {
transition: none !important;
}
.icon-btn {
@apply text-xl op75 hover:op100;
}
</style>
4 changes: 1 addition & 3 deletions playground/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ export default defineConfig({
},
plugins: [
Vue(),
Unocss({
transformCSS: true,
}),
Unocss(),
Inspect(),
Components({
dirs: [
Expand Down

0 comments on commit 9ddd2e8

Please sign in to comment.