safe-mdx 1.6.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -12
- package/dist/html/html-and-md.test.js +14 -41
- package/dist/html/html-and-md.test.js.map +1 -1
- package/dist/html/html-to-mdx-ast.d.ts +26 -1
- package/dist/html/html-to-mdx-ast.d.ts.map +1 -1
- package/dist/html/html-to-mdx-ast.js +40 -0
- package/dist/html/html-to-mdx-ast.js.map +1 -1
- package/dist/incremental-parse.d.ts +41 -0
- package/dist/incremental-parse.d.ts.map +1 -0
- package/dist/incremental-parse.js +139 -0
- package/dist/incremental-parse.js.map +1 -0
- package/dist/incremental-parse.test.d.ts +2 -0
- package/dist/incremental-parse.test.d.ts.map +1 -0
- package/dist/incremental-parse.test.js +299 -0
- package/dist/incremental-parse.test.js.map +1 -0
- package/dist/markdown-html.test.d.ts +2 -0
- package/dist/markdown-html.test.d.ts.map +1 -0
- package/dist/markdown-html.test.js +129 -0
- package/dist/markdown-html.test.js.map +1 -0
- package/dist/markdown.d.ts +3 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +4 -0
- package/dist/markdown.js.map +1 -0
- package/dist/parse.d.ts +9 -2
- package/dist/parse.d.ts.map +1 -1
- package/dist/parse.js +24 -12
- package/dist/parse.js.map +1 -1
- package/dist/safe-mdx.d.ts +13 -0
- package/dist/safe-mdx.d.ts.map +1 -1
- package/dist/safe-mdx.js +193 -24
- package/dist/safe-mdx.js.map +1 -1
- package/dist/safe-mdx.test.js +284 -11
- package/dist/safe-mdx.test.js.map +1 -1
- package/package.json +9 -1
- package/src/html/html-and-md.test.ts +15 -47
- package/src/html/html-to-mdx-ast.ts +53 -1
- package/src/incremental-parse.test.ts +315 -0
- package/src/incremental-parse.ts +219 -0
- package/src/markdown-html.test.tsx +144 -0
- package/src/markdown.ts +4 -0
- package/src/parse.ts +36 -13
- package/src/safe-mdx.test.tsx +357 -11
- package/src/safe-mdx.tsx +252 -26
package/src/parse.ts
CHANGED
|
@@ -5,9 +5,9 @@ import { Root, RootContent } from 'mdast'
|
|
|
5
5
|
import { remark } from 'remark'
|
|
6
6
|
import remarkGfm from 'remark-gfm'
|
|
7
7
|
import remarkMdx from 'remark-mdx'
|
|
8
|
-
import {
|
|
8
|
+
import { remarkMdxJsxNormalize } from './html/remark-mdx-jsx-normalize.ts'
|
|
9
9
|
|
|
10
|
-
export {
|
|
10
|
+
export { remarkMdxJsxNormalize }
|
|
11
11
|
|
|
12
12
|
/* ── Import extraction ──────────────────────────────────────────────── */
|
|
13
13
|
|
|
@@ -34,7 +34,7 @@ export function extractImports(ast: Root): MdxImport[] {
|
|
|
34
34
|
|
|
35
35
|
for (const node of ast.children) {
|
|
36
36
|
if (node.type !== 'mdxjsEsm') continue
|
|
37
|
-
const estree =
|
|
37
|
+
const estree = node.data?.estree
|
|
38
38
|
if (!estree) continue
|
|
39
39
|
|
|
40
40
|
for (const statement of estree.body) {
|
|
@@ -70,6 +70,38 @@ export function mdxParse(code: string) {
|
|
|
70
70
|
return file.data.ast as Root
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
export type MdxProcessorOptions = {
|
|
74
|
+
/** Extra remark plugins appended after safe-mdx's default MDX, frontmatter, and GFM parsers. */
|
|
75
|
+
remarkPlugins?: any[]
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function createMdxProcessor({
|
|
79
|
+
remarkPlugins = [],
|
|
80
|
+
}: MdxProcessorOptions = {}) {
|
|
81
|
+
const processor = remark()
|
|
82
|
+
.use(remarkMdx)
|
|
83
|
+
.use(remarkFrontmatter, ['yaml', 'toml'])
|
|
84
|
+
.use(remarkGfm)
|
|
85
|
+
|
|
86
|
+
for (const plugin of remarkPlugins) {
|
|
87
|
+
if (Array.isArray(plugin)) {
|
|
88
|
+
processor.use(plugin[0], ...plugin.slice(1))
|
|
89
|
+
} else {
|
|
90
|
+
processor.use(plugin)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return processor
|
|
95
|
+
.use(remarkMarkAndUnravel)
|
|
96
|
+
.use(() => {
|
|
97
|
+
return (tree, file) => {
|
|
98
|
+
file.data.ast = tree
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export type MdxProcessor = ReturnType<typeof createMdxProcessor>
|
|
104
|
+
|
|
73
105
|
/**
|
|
74
106
|
* https://github.com/mdx-js/mdx/blob/b3351fadcb6f78833a72757b7135dcfb8ab646fe/packages/mdx/lib/plugin/remark-mark-and-unravel.js
|
|
75
107
|
* A tiny plugin that unravels `<p><h1>x</h1></p>` but also
|
|
@@ -262,13 +294,4 @@ export async function resolveModules({
|
|
|
262
294
|
return result
|
|
263
295
|
}
|
|
264
296
|
|
|
265
|
-
const mdxProcessor =
|
|
266
|
-
.use(remarkMdx)
|
|
267
|
-
.use(remarkFrontmatter, ['yaml', 'toml'])
|
|
268
|
-
.use(remarkGfm)
|
|
269
|
-
.use(remarkMarkAndUnravel)
|
|
270
|
-
.use(() => {
|
|
271
|
-
return (tree, file) => {
|
|
272
|
-
file.data.ast = tree
|
|
273
|
-
}
|
|
274
|
-
})
|
|
297
|
+
export const mdxProcessor = createMdxProcessor()
|
package/src/safe-mdx.test.tsx
CHANGED
|
@@ -3818,7 +3818,7 @@ test('scope with function in spread attribute', () => {
|
|
|
3818
3818
|
expect(html).toMatchInlineSnapshot(`"<h1>Spread test</h1>"`)
|
|
3819
3819
|
})
|
|
3820
3820
|
|
|
3821
|
-
test('scope with .map and arrow function callback
|
|
3821
|
+
test('scope with .map and arrow function callback works without generate (safe interpreter)', () => {
|
|
3822
3822
|
const scope = {
|
|
3823
3823
|
items: [{ name: 'Alice' }, { name: 'Bob' }, { name: 'Charlie' }],
|
|
3824
3824
|
}
|
|
@@ -3828,16 +3828,8 @@ test('scope with .map and arrow function callback fails without generate', () =>
|
|
|
3828
3828
|
`
|
|
3829
3829
|
|
|
3830
3830
|
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
3831
|
-
expect(errors).toMatchInlineSnapshot(`
|
|
3832
|
-
|
|
3833
|
-
{
|
|
3834
|
-
"line": 1,
|
|
3835
|
-
"message": "Failed to evaluate expression: items.map(item => item.name).join(", "). Expected options.generate to be the "generate" function from "escodegen"",
|
|
3836
|
-
"type": "expression",
|
|
3837
|
-
},
|
|
3838
|
-
]
|
|
3839
|
-
`)
|
|
3840
|
-
expect(html).toMatchInlineSnapshot(`""`)
|
|
3831
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
3832
|
+
expect(html).toMatchInlineSnapshot(`"Alice, Bob, Charlie"`)
|
|
3841
3833
|
})
|
|
3842
3834
|
|
|
3843
3835
|
test('scope with .map and arrow function callback works with generate', () => {
|
|
@@ -3853,3 +3845,357 @@ test('scope with .map and arrow function callback works with generate', () => {
|
|
|
3853
3845
|
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
3854
3846
|
expect(html).toMatchInlineSnapshot(`"Alice, Bob, Charlie"`)
|
|
3855
3847
|
})
|
|
3848
|
+
|
|
3849
|
+
test('safe interpreter: arrow with block body and return', () => {
|
|
3850
|
+
const scope = {
|
|
3851
|
+
items: [1, 2, 3],
|
|
3852
|
+
}
|
|
3853
|
+
|
|
3854
|
+
const code = dedent`
|
|
3855
|
+
{items.map(x => { return x * 2 }).join(", ")}
|
|
3856
|
+
`
|
|
3857
|
+
|
|
3858
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
3859
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
3860
|
+
expect(html).toMatchInlineSnapshot(`"2, 4, 6"`)
|
|
3861
|
+
})
|
|
3862
|
+
|
|
3863
|
+
test('safe interpreter: arrow with multiple params', () => {
|
|
3864
|
+
const scope = {
|
|
3865
|
+
items: ['a', 'b', 'c'],
|
|
3866
|
+
}
|
|
3867
|
+
|
|
3868
|
+
const code = dedent`
|
|
3869
|
+
{items.map((item, i) => i + ":" + item).join(", ")}
|
|
3870
|
+
`
|
|
3871
|
+
|
|
3872
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
3873
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
3874
|
+
expect(html).toMatchInlineSnapshot(`"0:a, 1:b, 2:c"`)
|
|
3875
|
+
})
|
|
3876
|
+
|
|
3877
|
+
test('safe interpreter: arrow with object destructuring', () => {
|
|
3878
|
+
const scope = {
|
|
3879
|
+
items: [
|
|
3880
|
+
{ name: 'Alice', age: 30 },
|
|
3881
|
+
{ name: 'Bob', age: 25 },
|
|
3882
|
+
],
|
|
3883
|
+
}
|
|
3884
|
+
|
|
3885
|
+
const code = dedent`
|
|
3886
|
+
{items.map(({ name, age }) => name + "(" + age + ")").join(", ")}
|
|
3887
|
+
`
|
|
3888
|
+
|
|
3889
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
3890
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
3891
|
+
expect(html).toMatchInlineSnapshot(`"Alice(30), Bob(25)"`)
|
|
3892
|
+
})
|
|
3893
|
+
|
|
3894
|
+
test('safe interpreter: arrow with ternary expression', () => {
|
|
3895
|
+
const scope = {
|
|
3896
|
+
items: [
|
|
3897
|
+
{ name: 'Alice', active: true },
|
|
3898
|
+
{ name: 'Bob', active: false },
|
|
3899
|
+
],
|
|
3900
|
+
}
|
|
3901
|
+
|
|
3902
|
+
const code = dedent`
|
|
3903
|
+
{items.map(item => item.active ? item.name : "inactive").join(", ")}
|
|
3904
|
+
`
|
|
3905
|
+
|
|
3906
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
3907
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
3908
|
+
expect(html).toMatchInlineSnapshot(`"Alice, inactive"`)
|
|
3909
|
+
})
|
|
3910
|
+
|
|
3911
|
+
test('safe interpreter: .filter with arrow function', () => {
|
|
3912
|
+
const scope = {
|
|
3913
|
+
items: [1, 2, 3, 4, 5, 6],
|
|
3914
|
+
}
|
|
3915
|
+
|
|
3916
|
+
const code = dedent`
|
|
3917
|
+
{items.filter(x => x > 3).join(", ")}
|
|
3918
|
+
`
|
|
3919
|
+
|
|
3920
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
3921
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
3922
|
+
expect(html).toMatchInlineSnapshot(`"4, 5, 6"`)
|
|
3923
|
+
})
|
|
3924
|
+
|
|
3925
|
+
test('safe interpreter: .reduce with arrow function', () => {
|
|
3926
|
+
const scope = {
|
|
3927
|
+
items: [1, 2, 3, 4],
|
|
3928
|
+
}
|
|
3929
|
+
|
|
3930
|
+
const code = dedent`
|
|
3931
|
+
{items.reduce((acc, x) => acc + x, 0)}
|
|
3932
|
+
`
|
|
3933
|
+
|
|
3934
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
3935
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
3936
|
+
expect(html).toMatchInlineSnapshot(`"10"`)
|
|
3937
|
+
})
|
|
3938
|
+
|
|
3939
|
+
test('safe interpreter: chained .filter.map', () => {
|
|
3940
|
+
const scope = {
|
|
3941
|
+
users: [
|
|
3942
|
+
{ name: 'Alice', role: 'admin' },
|
|
3943
|
+
{ name: 'Bob', role: 'user' },
|
|
3944
|
+
{ name: 'Charlie', role: 'admin' },
|
|
3945
|
+
],
|
|
3946
|
+
}
|
|
3947
|
+
|
|
3948
|
+
const code = dedent`
|
|
3949
|
+
{users.filter(u => u.role === "admin").map(u => u.name).join(", ")}
|
|
3950
|
+
`
|
|
3951
|
+
|
|
3952
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
3953
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
3954
|
+
expect(html).toMatchInlineSnapshot(`"Alice, Charlie"`)
|
|
3955
|
+
})
|
|
3956
|
+
|
|
3957
|
+
test('safe interpreter: .find with arrow function', () => {
|
|
3958
|
+
const scope = {
|
|
3959
|
+
items: [
|
|
3960
|
+
{ id: 1, name: 'Alice' },
|
|
3961
|
+
{ id: 2, name: 'Bob' },
|
|
3962
|
+
],
|
|
3963
|
+
}
|
|
3964
|
+
|
|
3965
|
+
const code = dedent`
|
|
3966
|
+
{items.find(item => item.id === 2).name}
|
|
3967
|
+
`
|
|
3968
|
+
|
|
3969
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
3970
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
3971
|
+
expect(html).toMatchInlineSnapshot(`"Bob"`)
|
|
3972
|
+
})
|
|
3973
|
+
|
|
3974
|
+
test('safe interpreter: .some and .every with arrow functions', () => {
|
|
3975
|
+
const scope = {
|
|
3976
|
+
nums: [2, 4, 6],
|
|
3977
|
+
}
|
|
3978
|
+
|
|
3979
|
+
const code = dedent`
|
|
3980
|
+
{nums.every(n => n > 0) ? "all positive" : "nope"}
|
|
3981
|
+
`
|
|
3982
|
+
|
|
3983
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
3984
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
3985
|
+
expect(html).toMatchInlineSnapshot(`"all positive"`)
|
|
3986
|
+
})
|
|
3987
|
+
|
|
3988
|
+
test('safe interpreter: nested arrow functions', () => {
|
|
3989
|
+
const scope = {
|
|
3990
|
+
matrix: [[1, 2], [3, 4], [5, 6]],
|
|
3991
|
+
}
|
|
3992
|
+
|
|
3993
|
+
const code = dedent`
|
|
3994
|
+
{matrix.map(row => row.map(x => x * 10).join("-")).join(", ")}
|
|
3995
|
+
`
|
|
3996
|
+
|
|
3997
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
3998
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
3999
|
+
expect(html).toMatchInlineSnapshot(`"10-20, 30-40, 50-60"`)
|
|
4000
|
+
})
|
|
4001
|
+
|
|
4002
|
+
test('safe interpreter: arrow accessing outer scope variables', () => {
|
|
4003
|
+
const scope = {
|
|
4004
|
+
items: [1, 2, 3],
|
|
4005
|
+
multiplier: 5,
|
|
4006
|
+
}
|
|
4007
|
+
|
|
4008
|
+
const code = dedent`
|
|
4009
|
+
{items.map(x => x * multiplier).join(", ")}
|
|
4010
|
+
`
|
|
4011
|
+
|
|
4012
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
4013
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
4014
|
+
expect(html).toMatchInlineSnapshot(`"5, 10, 15"`)
|
|
4015
|
+
})
|
|
4016
|
+
|
|
4017
|
+
test('safe interpreter: arrow with block body and variable declaration', () => {
|
|
4018
|
+
const scope = {
|
|
4019
|
+
items: [{ first: 'John', last: 'Doe' }, { first: 'Jane', last: 'Smith' }],
|
|
4020
|
+
}
|
|
4021
|
+
|
|
4022
|
+
const code = dedent`
|
|
4023
|
+
{items.map(item => { const full = item.first + " " + item.last; return full }).join(", ")}
|
|
4024
|
+
`
|
|
4025
|
+
|
|
4026
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
4027
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
4028
|
+
expect(html).toMatchInlineSnapshot(`"John Doe, Jane Smith"`)
|
|
4029
|
+
})
|
|
4030
|
+
|
|
4031
|
+
test('safe interpreter: arrow with if/else in block body', () => {
|
|
4032
|
+
const scope = {
|
|
4033
|
+
items: [1, 2, 3, 4, 5],
|
|
4034
|
+
}
|
|
4035
|
+
|
|
4036
|
+
const code = dedent`
|
|
4037
|
+
{items.map(x => { if (x > 3) { return "big" } else { return "small" } }).join(", ")}
|
|
4038
|
+
`
|
|
4039
|
+
|
|
4040
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
4041
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
4042
|
+
expect(html).toMatchInlineSnapshot(`"small, small, small, big, big"`)
|
|
4043
|
+
})
|
|
4044
|
+
|
|
4045
|
+
test('safe interpreter: .sort with comparator arrow', () => {
|
|
4046
|
+
const scope = {
|
|
4047
|
+
items: [3, 1, 4, 1, 5],
|
|
4048
|
+
}
|
|
4049
|
+
|
|
4050
|
+
const code = dedent`
|
|
4051
|
+
{items.sort((a, b) => a - b).join(", ")}
|
|
4052
|
+
`
|
|
4053
|
+
|
|
4054
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
4055
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
4056
|
+
expect(html).toMatchInlineSnapshot(`"1, 1, 3, 4, 5"`)
|
|
4057
|
+
})
|
|
4058
|
+
|
|
4059
|
+
test('safe interpreter: arrow in JSX attribute', () => {
|
|
4060
|
+
const scope = {
|
|
4061
|
+
items: [{ name: 'Alice' }, { name: 'Bob' }],
|
|
4062
|
+
}
|
|
4063
|
+
|
|
4064
|
+
const code = dedent`
|
|
4065
|
+
<Heading level={items.map(i => i.name).join(", ")}>Title</Heading>
|
|
4066
|
+
`
|
|
4067
|
+
|
|
4068
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
4069
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
4070
|
+
expect(html).toMatchInlineSnapshot(`"<h1>Title</h1>"`)
|
|
4071
|
+
})
|
|
4072
|
+
|
|
4073
|
+
test('safe interpreter: arrow with array destructuring', () => {
|
|
4074
|
+
const scope = {
|
|
4075
|
+
pairs: [['a', 1], ['b', 2], ['c', 3]],
|
|
4076
|
+
}
|
|
4077
|
+
|
|
4078
|
+
const code = dedent`
|
|
4079
|
+
{pairs.map(([letter, num]) => letter + num).join(", ")}
|
|
4080
|
+
`
|
|
4081
|
+
|
|
4082
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
4083
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
4084
|
+
expect(html).toMatchInlineSnapshot(`"a1, b2, c3"`)
|
|
4085
|
+
})
|
|
4086
|
+
|
|
4087
|
+
test('safe interpreter: calling scope functions inside arrow callback', () => {
|
|
4088
|
+
const scope = {
|
|
4089
|
+
items: [{ name: 'alice' }, { name: 'bob' }],
|
|
4090
|
+
formatName: (s: string) => s.toUpperCase(),
|
|
4091
|
+
}
|
|
4092
|
+
|
|
4093
|
+
const code = dedent`
|
|
4094
|
+
{items.map(item => formatName(item.name)).join(", ")}
|
|
4095
|
+
`
|
|
4096
|
+
|
|
4097
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
4098
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
4099
|
+
expect(html).toMatchInlineSnapshot(`"ALICE, BOB"`)
|
|
4100
|
+
})
|
|
4101
|
+
|
|
4102
|
+
test('safe interpreter: calling scope function with multiple args inside arrow', () => {
|
|
4103
|
+
const scope = {
|
|
4104
|
+
items: [1, 2, 3],
|
|
4105
|
+
add: (a: number, b: number) => a + b,
|
|
4106
|
+
base: 10,
|
|
4107
|
+
}
|
|
4108
|
+
|
|
4109
|
+
const code = dedent`
|
|
4110
|
+
{items.map(x => add(x, base)).join(", ")}
|
|
4111
|
+
`
|
|
4112
|
+
|
|
4113
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
4114
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
4115
|
+
expect(html).toMatchInlineSnapshot(`"11, 12, 13"`)
|
|
4116
|
+
})
|
|
4117
|
+
|
|
4118
|
+
test('safe interpreter: scope function returning object used in arrow', () => {
|
|
4119
|
+
const scope = {
|
|
4120
|
+
ids: [1, 2, 3],
|
|
4121
|
+
getUser: (id: number) => ({ id, name: 'User' + id }),
|
|
4122
|
+
}
|
|
4123
|
+
|
|
4124
|
+
const code = dedent`
|
|
4125
|
+
{ids.map(id => getUser(id).name).join(", ")}
|
|
4126
|
+
`
|
|
4127
|
+
|
|
4128
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
4129
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
4130
|
+
expect(html).toMatchInlineSnapshot(`"User1, User2, User3"`)
|
|
4131
|
+
})
|
|
4132
|
+
|
|
4133
|
+
test('safe interpreter: arrow with default parameter', () => {
|
|
4134
|
+
const scope = {
|
|
4135
|
+
items: [undefined, 'hello', undefined],
|
|
4136
|
+
fallback: 'default',
|
|
4137
|
+
}
|
|
4138
|
+
|
|
4139
|
+
const code = dedent`
|
|
4140
|
+
{items.map((x = fallback) => x).join(", ")}
|
|
4141
|
+
`
|
|
4142
|
+
|
|
4143
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
4144
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
4145
|
+
expect(html).toMatchInlineSnapshot(`"default, hello, default"`)
|
|
4146
|
+
})
|
|
4147
|
+
|
|
4148
|
+
test('scope with template literal in expression', () => {
|
|
4149
|
+
const scope = {
|
|
4150
|
+
name: 'World',
|
|
4151
|
+
count: 3,
|
|
4152
|
+
}
|
|
4153
|
+
|
|
4154
|
+
const code = dedent`
|
|
4155
|
+
{${'`'}Hello ${'${'}name${'}'}, you have ${'${'}count${'}'} items${'`'}}
|
|
4156
|
+
`
|
|
4157
|
+
|
|
4158
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
4159
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
4160
|
+
expect(html).toMatchInlineSnapshot(`"Hello World, you have 3 items"`)
|
|
4161
|
+
})
|
|
4162
|
+
|
|
4163
|
+
test('scope with tagged template literal function', () => {
|
|
4164
|
+
const myTag = (strings: TemplateStringsArray, ...values: any[]) => {
|
|
4165
|
+
return strings.reduce((result, str, i) => {
|
|
4166
|
+
return result + str + (values[i] !== undefined ? String(values[i]).toUpperCase() : '')
|
|
4167
|
+
}, '')
|
|
4168
|
+
}
|
|
4169
|
+
|
|
4170
|
+
const scope = {
|
|
4171
|
+
myTag,
|
|
4172
|
+
name: 'world',
|
|
4173
|
+
}
|
|
4174
|
+
|
|
4175
|
+
const code = `{myTag${'`'}hello ${'${'}name${'}'}${'`'}}`
|
|
4176
|
+
|
|
4177
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope, { generate })
|
|
4178
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
4179
|
+
expect(html).toMatchInlineSnapshot(`"hello WORLD"`)
|
|
4180
|
+
})
|
|
4181
|
+
|
|
4182
|
+
test('scope with tagged template literal without generate', () => {
|
|
4183
|
+
const myTag = (strings: TemplateStringsArray, ...values: any[]) => {
|
|
4184
|
+
return strings.reduce((result, str, i) => {
|
|
4185
|
+
return result + str + (values[i] !== undefined ? String(values[i]).toUpperCase() : '')
|
|
4186
|
+
}, '')
|
|
4187
|
+
}
|
|
4188
|
+
|
|
4189
|
+
const scope = {
|
|
4190
|
+
myTag,
|
|
4191
|
+
name: 'world',
|
|
4192
|
+
}
|
|
4193
|
+
|
|
4194
|
+
const code = `{myTag${'`'}hello ${'${'}name${'}'}${'`'}}`
|
|
4195
|
+
|
|
4196
|
+
const { html, errors } = render(code, undefined, undefined, undefined, scope)
|
|
4197
|
+
expect(errors).toMatchInlineSnapshot(`[]`)
|
|
4198
|
+
expect(html).toMatchInlineSnapshot(`"hello WORLD"`)
|
|
4199
|
+
})
|
|
4200
|
+
|
|
4201
|
+
|