Skip to content

Commit 7396c9f

Browse files
committed
feat(rsc): support directive pattern transform
1 parent 7a40ee7 commit 7396c9f

File tree

1 file changed

+39
-8
lines changed
  • packages/plugin-rsc/src/transforms

1 file changed

+39
-8
lines changed

packages/plugin-rsc/src/transforms/hoist.ts

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,21 @@ import type { Program } from 'estree'
33
import { walk } from 'estree-walker'
44
import MagicString from 'magic-string'
55
import { analyze } from 'periscopic'
6-
import { hasDirective } from './utils'
76

87
export function transformHoistInlineDirective(
98
input: string,
109
ast: Program,
1110
{
1211
runtime,
13-
directive,
1412
rejectNonAsyncFunction,
1513
...options
1614
}: {
17-
runtime: (value: string, name: string) => string
18-
directive: string
15+
runtime: (
16+
value: string,
17+
name: string,
18+
meta: { directiveMatch: RegExpMatchArray },
19+
) => string
20+
directive: string | RegExp
1921
rejectNonAsyncFunction?: boolean
2022
encode?: (value: string) => string
2123
decode?: (value: string) => string
@@ -26,6 +28,10 @@ export function transformHoistInlineDirective(
2628
names: string[]
2729
} {
2830
const output = new MagicString(input)
31+
const directiveRegex =
32+
typeof options.directive === 'string'
33+
? exactRegex(options.directive)
34+
: options.directive
2935

3036
// re-export somehow confuses periscopic scopes so remove them before analysis
3137
walk(ast, {
@@ -48,12 +54,13 @@ export function transformHoistInlineDirective(
4854
(node.type === 'FunctionExpression' ||
4955
node.type === 'FunctionDeclaration' ||
5056
node.type === 'ArrowFunctionExpression') &&
51-
node.body.type === 'BlockStatement' &&
52-
hasDirective(node.body.body, directive)
57+
node.body.type === 'BlockStatement'
5358
) {
59+
const match = matchDirective(node.body.body, directiveRegex)
60+
if (!match) return
5461
if (!node.async && rejectNonAsyncFunction) {
5562
throw Object.assign(
56-
new Error(`"${directive}" doesn't allow non async function`),
63+
new Error(`"${directiveRegex}" doesn't allow non async function`),
5764
{
5865
pos: node.start,
5966
},
@@ -116,7 +123,9 @@ export function transformHoistInlineDirective(
116123
output.move(node.start, node.end, input.length)
117124

118125
// replace original declartion with action register + bind
119-
let newCode = `/* #__PURE__ */ ${runtime(newName, newName)}`
126+
let newCode = `/* #__PURE__ */ ${runtime(newName, newName, {
127+
directiveMatch: match,
128+
})}`
120129
if (bindVars.length > 0) {
121130
const bindArgs = options.encode
122131
? options.encode('[' + bindVars.join(', ') + ']')
@@ -140,3 +149,25 @@ export function transformHoistInlineDirective(
140149
names,
141150
}
142151
}
152+
153+
const exactRegex = (s: string): RegExp =>
154+
new RegExp('^' + s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') + '$', 'u')
155+
156+
function matchDirective(
157+
body: Program['body'],
158+
directive: RegExp,
159+
): RegExpMatchArray | undefined {
160+
for (const stable of body) {
161+
if (
162+
stable.type === 'ExpressionStatement' &&
163+
stable.expression.type === 'Literal' &&
164+
typeof stable.expression.value === 'string' &&
165+
stable.expression.value.match(directive)
166+
) {
167+
const match = stable.expression.value.match(directive)
168+
if (match) {
169+
return match
170+
}
171+
}
172+
}
173+
}

0 commit comments

Comments
 (0)