@orgajs/orgx 1.0.7 → 2.0.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/LICENSE.org +22 -0
- package/dist/index.d.ts +11 -5
- package/dist/lib/compile.d.ts +45 -0
- package/dist/lib/condition.browser.d.ts +1 -0
- package/dist/lib/condition.d.ts +1 -0
- package/dist/lib/core.d.ts +57 -0
- package/dist/lib/evaluate.d.ts +27 -0
- package/dist/lib/plugin/recma-document.d.ts +63 -0
- package/dist/lib/plugin/recma-jsx-build.d.ts +14 -0
- package/dist/lib/plugin/recma-jsx-rewrite.d.ts +50 -0
- package/dist/lib/plugin/recma-stringify.d.ts +13 -0
- package/dist/lib/plugin/rehype-recma.d.ts +49 -0
- package/dist/lib/run.d.ts +26 -0
- package/dist/lib/util/estree-util-create.d.ts +13 -0
- package/dist/lib/util/estree-util-declaration-to-expression.d.ts +19 -0
- package/dist/lib/util/estree-util-is-declaration.d.ts +15 -0
- package/dist/lib/util/estree-util-specifiers-to-declarations.d.ts +14 -0
- package/dist/lib/util/estree-util-to-binary-addition.d.ts +8 -0
- package/dist/lib/util/estree-util-to-id-or-member-expression.d.ts +11 -0
- package/dist/lib/util/render-error.d.ts +2 -0
- package/dist/lib/util/resolve-evaluate-options.d.ts +66 -0
- package/dist/lib/util/resolve-file-and-options.d.ts +16 -0
- package/index.js +14 -0
- package/lib/compile.js +54 -0
- package/lib/condition.browser.js +1 -0
- package/lib/condition.js +3 -0
- package/lib/core.js +100 -0
- package/lib/evaluate.js +41 -0
- package/lib/plugin/recma-document.js +607 -0
- package/lib/plugin/recma-jsx-build.js +53 -0
- package/lib/plugin/recma-jsx-rewrite.js +616 -0
- package/lib/plugin/recma-stringify.js +42 -0
- package/lib/plugin/rehype-recma.js +218 -0
- package/lib/run.js +31 -0
- package/lib/types.d.ts +46 -0
- package/lib/util/estree-util-create.js +27 -0
- package/lib/util/estree-util-declaration-to-expression.js +32 -0
- package/lib/util/estree-util-is-declaration.js +20 -0
- package/lib/util/estree-util-specifiers-to-declarations.js +90 -0
- package/lib/util/estree-util-to-binary-addition.js +23 -0
- package/lib/util/estree-util-to-id-or-member-expression.js +108 -0
- package/lib/util/render-error.js +91 -0
- package/lib/util/resolve-evaluate-options.js +64 -0
- package/lib/util/resolve-file-and-options.js +40 -0
- package/package.json +36 -29
- package/CHANGELOG.md +0 -71
- package/dist/compile.d.ts +0 -6
- package/dist/compile.d.ts.map +0 -1
- package/dist/compile.js +0 -12
- package/dist/compile.js.map +0 -1
- package/dist/estree/create.d.ts +0 -2
- package/dist/estree/create.d.ts.map +0 -1
- package/dist/estree/create.js +0 -14
- package/dist/estree/create.js.map +0 -1
- package/dist/estree/declaration-to-expression.d.ts +0 -3
- package/dist/estree/declaration-to-expression.d.ts.map +0 -1
- package/dist/estree/declaration-to-expression.js +0 -12
- package/dist/estree/declaration-to-expression.js.map +0 -1
- package/dist/estree/error.d.ts +0 -61
- package/dist/estree/error.d.ts.map +0 -1
- package/dist/estree/error.js +0 -87
- package/dist/estree/error.js.map +0 -1
- package/dist/estree/is-declaration.d.ts +0 -3
- package/dist/estree/is-declaration.d.ts.map +0 -1
- package/dist/estree/is-declaration.js +0 -9
- package/dist/estree/is-declaration.js.map +0 -1
- package/dist/estree/position-from-estree.d.ts +0 -13
- package/dist/estree/position-from-estree.d.ts.map +0 -1
- package/dist/estree/position-from-estree.js +0 -34
- package/dist/estree/position-from-estree.js.map +0 -1
- package/dist/estree/specifiers-to-object-pattern.d.ts +0 -5
- package/dist/estree/specifiers-to-object-pattern.d.ts.map +0 -1
- package/dist/estree/specifiers-to-object-pattern.js +0 -33
- package/dist/estree/specifiers-to-object-pattern.js.map +0 -1
- package/dist/evaluate.d.ts +0 -22
- package/dist/evaluate.d.ts.map +0 -1
- package/dist/evaluate.js +0 -27
- package/dist/evaluate.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -11
- package/dist/index.js.map +0 -1
- package/dist/plugin/estree-jsx-build.d.ts +0 -6
- package/dist/plugin/estree-jsx-build.d.ts.map +0 -1
- package/dist/plugin/estree-jsx-build.js +0 -38
- package/dist/plugin/estree-jsx-build.js.map +0 -1
- package/dist/plugin/estree-jsx-rewrite.d.ts +0 -6
- package/dist/plugin/estree-jsx-rewrite.d.ts.map +0 -1
- package/dist/plugin/estree-jsx-rewrite.js +0 -214
- package/dist/plugin/estree-jsx-rewrite.js.map +0 -1
- package/dist/plugin/estree-stringify.d.ts +0 -2
- package/dist/plugin/estree-stringify.d.ts.map +0 -1
- package/dist/plugin/estree-stringify.js +0 -127
- package/dist/plugin/estree-stringify.js.map +0 -1
- package/dist/plugin/estree-wrap-in-content.d.ts +0 -18
- package/dist/plugin/estree-wrap-in-content.d.ts.map +0 -1
- package/dist/plugin/estree-wrap-in-content.js +0 -375
- package/dist/plugin/estree-wrap-in-content.js.map +0 -1
- package/dist/plugin/rehype-estree.d.ts +0 -12
- package/dist/plugin/rehype-estree.d.ts.map +0 -1
- package/dist/plugin/rehype-estree.js +0 -122
- package/dist/plugin/rehype-estree.js.map +0 -1
- package/dist/plugin/rehype-set-layout.d.ts +0 -6
- package/dist/plugin/rehype-set-layout.d.ts.map +0 -1
- package/dist/plugin/rehype-set-layout.js +0 -30
- package/dist/plugin/rehype-set-layout.js.map +0 -1
- package/dist/processor.d.ts +0 -14
- package/dist/processor.d.ts.map +0 -1
- package/dist/processor.js +0 -52
- package/dist/processor.js.map +0 -1
- package/dist/utils/remove-quotes.d.ts +0 -3
- package/dist/utils/remove-quotes.d.ts.map +0 -1
- package/dist/utils/remove-quotes.js +0 -6
- package/dist/utils/remove-quotes.js.map +0 -1
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('estree-jsx').Program} Program
|
|
3
|
+
* @typedef {import('estree-jsx').Expression} Expression
|
|
4
|
+
* @typedef {import('estree-jsx').ModuleDeclaration} ModuleDeclaration
|
|
5
|
+
* @typedef {import('hast').Root} Root
|
|
6
|
+
* @typedef {import('hast-util-to-estree').Handle} Handle
|
|
7
|
+
* @typedef {import('hast-util-to-estree').Options} HastToEstreeOptions
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {'html' | 'react'} ElementAttributeNameCase
|
|
12
|
+
* Specify casing to use for attribute names.
|
|
13
|
+
*
|
|
14
|
+
* HTML casing is for example `class`, `stroke-linecap`, `xml:lang`.
|
|
15
|
+
* React casing is for example `className`, `strokeLinecap`, `xmlLang`.
|
|
16
|
+
*
|
|
17
|
+
* @typedef {'css' | 'dom'} StylePropertyNameCase
|
|
18
|
+
* Casing to use for property names in `style` objects.
|
|
19
|
+
*
|
|
20
|
+
* CSS casing is for example `background-color` and `-webkit-line-clamp`.
|
|
21
|
+
* DOM casing is for example `backgroundColor` and `WebkitLineClamp`.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @typedef MoreOptions
|
|
26
|
+
* Configuration for internal plugin `rehype-recma`.
|
|
27
|
+
* @property {ElementAttributeNameCase | undefined | null} [elementAttributeNameCase='react']
|
|
28
|
+
* Specify casing to use for attribute names.
|
|
29
|
+
*
|
|
30
|
+
* This casing is used for hast elements, not for embedded Org JSX nodes
|
|
31
|
+
* (components that someone authored manually).
|
|
32
|
+
* @property {StylePropertyNameCase | undefined | null} [stylePropertyNameCase='dom']
|
|
33
|
+
* Specify casing to use for property names in `style` objects.
|
|
34
|
+
*
|
|
35
|
+
* This casing is used for hast elements, not for embedded Org JSX nodes
|
|
36
|
+
* (components that someone authored manually).
|
|
37
|
+
* @property {boolean} [skipImport=false] - Whether to skip imports
|
|
38
|
+
* @property {string[]} [parseJSX=['jsx.value']] - Specify which hast properties to parse as JSX.
|
|
39
|
+
*
|
|
40
|
+
* @typedef {HastToEstreeOptions & MoreOptions} Options
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
import { toEstree } from 'hast-util-to-estree'
|
|
44
|
+
import { Parser } from 'acorn'
|
|
45
|
+
import jsx from 'acorn-jsx'
|
|
46
|
+
import renderError from '../util/render-error.js'
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A plugin to transform an HTML (hast) tree to a JS (estree).
|
|
50
|
+
* `hast-util-to-estree` does all the work for us!
|
|
51
|
+
*
|
|
52
|
+
* @type {import('unified').Plugin<[Options | undefined] | [], Root, Program>}
|
|
53
|
+
*/
|
|
54
|
+
export function rehypeRecma(options = {}) {
|
|
55
|
+
const {
|
|
56
|
+
skipImport = false,
|
|
57
|
+
parseJSX = ['jsx.value'],
|
|
58
|
+
...otherOptions
|
|
59
|
+
} = options
|
|
60
|
+
const handlers = options.handlers || {}
|
|
61
|
+
|
|
62
|
+
for (const p of parseJSX) {
|
|
63
|
+
const [key, ...rest] = p.split('.')
|
|
64
|
+
if (!key) {
|
|
65
|
+
throw new Error('somethings wrong')
|
|
66
|
+
}
|
|
67
|
+
const path = rest.length > 0 ? rest.join('.') : 'value'
|
|
68
|
+
handlers[key] = jsxHandle(path, skipImport)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return (tree) => {
|
|
72
|
+
const data = tree.data || {}
|
|
73
|
+
const { layout, ...otherData } = data
|
|
74
|
+
/** @type {ModuleDeclaration[]} */
|
|
75
|
+
const prepand = []
|
|
76
|
+
if (typeof layout === 'string') {
|
|
77
|
+
prepand.push({
|
|
78
|
+
type: 'ImportDeclaration',
|
|
79
|
+
specifiers: [
|
|
80
|
+
{
|
|
81
|
+
type: 'ImportDefaultSpecifier',
|
|
82
|
+
local: {
|
|
83
|
+
type: 'Identifier',
|
|
84
|
+
name: 'OrgaLayout',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
source: {
|
|
89
|
+
type: 'Literal',
|
|
90
|
+
value: `${layout}`,
|
|
91
|
+
raw: `'${layout}'`,
|
|
92
|
+
},
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
Object.entries(otherData).forEach(([k, v]) => {
|
|
96
|
+
prepand.push(createExport(k, v))
|
|
97
|
+
})
|
|
98
|
+
const estree = toEstree(tree, { ...otherOptions, handlers })
|
|
99
|
+
estree.body.unshift(...prepand)
|
|
100
|
+
return estree
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @param {string} p
|
|
106
|
+
* @param {any} o
|
|
107
|
+
* @returns {any}
|
|
108
|
+
*/
|
|
109
|
+
function deepGet(p, o) {
|
|
110
|
+
return p.split('.').reduce((a, v) => a[v], o)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const jsxParser = Parser.extend(jsx())
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @param {string} code
|
|
117
|
+
*/
|
|
118
|
+
const parse = (code) => {
|
|
119
|
+
try {
|
|
120
|
+
return jsxParser.parse(code, {
|
|
121
|
+
sourceType: 'module',
|
|
122
|
+
ecmaVersion: 2020,
|
|
123
|
+
})
|
|
124
|
+
} catch (err) {
|
|
125
|
+
// @ts-ignore
|
|
126
|
+
return renderError(err)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @param {import('acorn').Node | Program} node
|
|
132
|
+
* @returns {node is Program}
|
|
133
|
+
*/
|
|
134
|
+
function isProgram(node) {
|
|
135
|
+
return node.type === 'Program'
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
*
|
|
140
|
+
* @param {string} path
|
|
141
|
+
* @param {boolean} skipImport
|
|
142
|
+
* @returns {Handle}
|
|
143
|
+
*/
|
|
144
|
+
function jsxHandle(path, skipImport) {
|
|
145
|
+
/** @type {Handle} */
|
|
146
|
+
const handle = (node, state) => {
|
|
147
|
+
const estree = parse(deepGet(path, node))
|
|
148
|
+
/** @type {Expression[]} */
|
|
149
|
+
const expressions = []
|
|
150
|
+
if (isProgram(estree)) {
|
|
151
|
+
estree.body.forEach((child) => {
|
|
152
|
+
if (child.type === 'ImportDeclaration') {
|
|
153
|
+
if (!skipImport) {
|
|
154
|
+
state.esm.push(child)
|
|
155
|
+
}
|
|
156
|
+
return false
|
|
157
|
+
} else if (child.type === 'ExpressionStatement') {
|
|
158
|
+
expressions.push(child.expression)
|
|
159
|
+
} else if (
|
|
160
|
+
child.type === 'ExportDefaultDeclaration' ||
|
|
161
|
+
child.type === 'ExportNamedDeclaration'
|
|
162
|
+
) {
|
|
163
|
+
state.esm.push(child)
|
|
164
|
+
} else {
|
|
165
|
+
throw new Error(`unexpected node: ${child.type}`)
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// @ts-ignore it works
|
|
171
|
+
return expressions
|
|
172
|
+
}
|
|
173
|
+
return handle
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @param {string} text
|
|
178
|
+
* @returns {string}
|
|
179
|
+
*/
|
|
180
|
+
function removeQuotes(text) {
|
|
181
|
+
return text.trim().replace(/^["'](.+(?=["']$))["']$/, '$1')
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @param {string} k
|
|
186
|
+
* @param {any} v
|
|
187
|
+
* @returns {ModuleDeclaration}
|
|
188
|
+
*/
|
|
189
|
+
function createExport(k, v) {
|
|
190
|
+
/** @type {(text: string) => Expression} */
|
|
191
|
+
const createLiteral = (text) => {
|
|
192
|
+
const value = removeQuotes(`${text}`)
|
|
193
|
+
return { type: 'Literal', value, raw: `'${value}'` }
|
|
194
|
+
}
|
|
195
|
+
/** @type {Expression} */
|
|
196
|
+
const init = Array.isArray(v)
|
|
197
|
+
? {
|
|
198
|
+
type: 'ArrayExpression',
|
|
199
|
+
elements: v.map(createLiteral),
|
|
200
|
+
}
|
|
201
|
+
: createLiteral(v)
|
|
202
|
+
return {
|
|
203
|
+
type: 'ExportNamedDeclaration',
|
|
204
|
+
declaration: {
|
|
205
|
+
type: 'VariableDeclaration',
|
|
206
|
+
declarations: [
|
|
207
|
+
{
|
|
208
|
+
type: 'VariableDeclarator',
|
|
209
|
+
id: { type: 'Identifier', name: k },
|
|
210
|
+
init,
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
kind: 'const',
|
|
214
|
+
},
|
|
215
|
+
specifiers: [],
|
|
216
|
+
source: null,
|
|
217
|
+
}
|
|
218
|
+
}
|
package/lib/run.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** @type {new (code: string, ...args: Array<unknown>) => Function} **/
|
|
2
|
+
const AsyncFunction = Object.getPrototypeOf(run).constructor
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Asynchronously run code.
|
|
6
|
+
*
|
|
7
|
+
* @param {{toString(): string}} file
|
|
8
|
+
* JS document to run.
|
|
9
|
+
* @param {unknown} options
|
|
10
|
+
* Parameter.
|
|
11
|
+
* @return {Promise<any>}
|
|
12
|
+
* Anything.
|
|
13
|
+
*/
|
|
14
|
+
export async function run(file, options) {
|
|
15
|
+
return new AsyncFunction(String(file))(options)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Synchronously run code.
|
|
20
|
+
*
|
|
21
|
+
* @param {{toString(): string}} file
|
|
22
|
+
* JS document to run.
|
|
23
|
+
* @param {unknown} options
|
|
24
|
+
* Parameter.
|
|
25
|
+
* @return {any}
|
|
26
|
+
* Anything.
|
|
27
|
+
*/
|
|
28
|
+
export function runSync(file, options) {
|
|
29
|
+
// eslint-disable-next-line no-new-func
|
|
30
|
+
return new Function(String(file))(options)
|
|
31
|
+
}
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
type FunctionComponent<Props> = (props: Props) => JSX.Element | null
|
|
2
|
+
type ClassComponent<Props> = new (props: Props) => JSX.ElementClass
|
|
3
|
+
type Component<Props> =
|
|
4
|
+
| FunctionComponent<Props>
|
|
5
|
+
| ClassComponent<Props>
|
|
6
|
+
| keyof JSX.IntrinsicElements
|
|
7
|
+
|
|
8
|
+
interface NestedOrgComponents {
|
|
9
|
+
[key: string]: NestedOrgComponents | Component<any>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type OrgComponents = NestedOrgComponents & {
|
|
13
|
+
[Key in keyof JSX.IntrinsicElements]?: Component<JSX.IntrinsicElements[Key]>
|
|
14
|
+
} & {
|
|
15
|
+
/**
|
|
16
|
+
* If a wrapper component is defined, the org content will be wrapped inside of it.
|
|
17
|
+
*/
|
|
18
|
+
wrapper?: Component<any>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface OrgProps {
|
|
22
|
+
/**
|
|
23
|
+
* Which props exactly may be passed into the component depends on the contents of the org
|
|
24
|
+
* file.
|
|
25
|
+
*/
|
|
26
|
+
[key: string]: unknown
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* This prop may be used to customize how certain components are rendered.
|
|
30
|
+
*/
|
|
31
|
+
components?: OrgComponents
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type OrgContent = (props: OrgProps) => JSX.Element
|
|
35
|
+
|
|
36
|
+
export interface OrgModule {
|
|
37
|
+
/**
|
|
38
|
+
* This could be any value that is exported from the org file.
|
|
39
|
+
*/
|
|
40
|
+
[key: string]: unknown
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A functional JSX component which renders the content of the org file.
|
|
44
|
+
*/
|
|
45
|
+
default: OrgContent
|
|
46
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('estree-jsx').Node} Node
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {Node} from
|
|
7
|
+
* Node to take from.
|
|
8
|
+
* @param {Node} to
|
|
9
|
+
* Node to add to.
|
|
10
|
+
* @returns {void}
|
|
11
|
+
* Nothing.
|
|
12
|
+
*/
|
|
13
|
+
export function create(from, to) {
|
|
14
|
+
/** @type {Array<keyof Node>} */
|
|
15
|
+
// @ts-expect-error: `start`, `end`, `comments` are custom Acorn fields.
|
|
16
|
+
const fields = ['start', 'end', 'loc', 'range', 'comments']
|
|
17
|
+
let index = -1
|
|
18
|
+
|
|
19
|
+
while (++index < fields.length) {
|
|
20
|
+
const field = fields[index]
|
|
21
|
+
|
|
22
|
+
if (field in from) {
|
|
23
|
+
// @ts-expect-error: assume they’re settable.
|
|
24
|
+
to[field] = from[field]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('estree-jsx').Declaration} Declaration
|
|
3
|
+
* @typedef {import('estree-jsx').Expression} Expression
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Turn a declaration into an expression.
|
|
8
|
+
*
|
|
9
|
+
* Doesn’t work for variable declarations, but that’s fine for our use case
|
|
10
|
+
* because currently we’re using this utility for export default declarations,
|
|
11
|
+
* which can’t contain variable declarations.
|
|
12
|
+
*
|
|
13
|
+
* @param {Declaration} declaration
|
|
14
|
+
* Declaration.
|
|
15
|
+
* @returns {Expression}
|
|
16
|
+
* Expression.
|
|
17
|
+
*/
|
|
18
|
+
export function declarationToExpression(declaration) {
|
|
19
|
+
if (declaration.type === 'FunctionDeclaration') {
|
|
20
|
+
return {...declaration, type: 'FunctionExpression'}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (declaration.type === 'ClassDeclaration') {
|
|
24
|
+
return {...declaration, type: 'ClassExpression'}
|
|
25
|
+
/* Internal utility so the next shouldn’t happen or a maintainer is making a
|
|
26
|
+
* mistake. */
|
|
27
|
+
/* c8 ignore next 4 */
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Probably `VariableDeclaration`.
|
|
31
|
+
throw new Error('Cannot turn `' + declaration.type + '` into an expression')
|
|
32
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('estree-jsx').Node} Node
|
|
3
|
+
* @typedef {import('estree-jsx').Declaration} Declaration
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Check if `node` is a declaration.
|
|
8
|
+
*
|
|
9
|
+
* @param {Node} node
|
|
10
|
+
* Node to check.
|
|
11
|
+
* @returns {node is Declaration}
|
|
12
|
+
* Whether `node` is a declaration.
|
|
13
|
+
*/
|
|
14
|
+
export function isDeclaration(node) {
|
|
15
|
+
return Boolean(
|
|
16
|
+
node.type === 'FunctionDeclaration' ||
|
|
17
|
+
node.type === 'ClassDeclaration' ||
|
|
18
|
+
node.type === 'VariableDeclaration'
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('estree-jsx').AssignmentProperty} AssignmentProperty
|
|
3
|
+
* @typedef {import('estree-jsx').ExportSpecifier} ExportSpecifier
|
|
4
|
+
* @typedef {import('estree-jsx').Expression} Expression
|
|
5
|
+
* @typedef {import('estree-jsx').Identifier} Identifier
|
|
6
|
+
* @typedef {import('estree-jsx').ImportDefaultSpecifier} ImportDefaultSpecifier
|
|
7
|
+
* @typedef {import('estree-jsx').ImportNamespaceSpecifier} ImportNamespaceSpecifier
|
|
8
|
+
* @typedef {import('estree-jsx').ImportSpecifier} ImportSpecifier
|
|
9
|
+
* @typedef {import('estree-jsx').VariableDeclarator} VariableDeclarator
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {create} from './estree-util-create.js'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {Array<ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier | ExportSpecifier>} specifiers
|
|
16
|
+
* @param {Expression} init
|
|
17
|
+
* @returns {Array<VariableDeclarator>}
|
|
18
|
+
*/
|
|
19
|
+
export function specifiersToDeclarations(specifiers, init) {
|
|
20
|
+
let index = -1
|
|
21
|
+
/** @type {Array<VariableDeclarator>} */
|
|
22
|
+
const declarations = []
|
|
23
|
+
/** @type {Array<ImportSpecifier | ImportDefaultSpecifier | ExportSpecifier>} */
|
|
24
|
+
const otherSpecifiers = []
|
|
25
|
+
// Can only be one according to JS syntax.
|
|
26
|
+
/** @type {ImportNamespaceSpecifier | undefined} */
|
|
27
|
+
let importNamespaceSpecifier
|
|
28
|
+
|
|
29
|
+
while (++index < specifiers.length) {
|
|
30
|
+
const specifier = specifiers[index]
|
|
31
|
+
|
|
32
|
+
if (specifier.type === 'ImportNamespaceSpecifier') {
|
|
33
|
+
importNamespaceSpecifier = specifier
|
|
34
|
+
} else {
|
|
35
|
+
otherSpecifiers.push(specifier)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (importNamespaceSpecifier) {
|
|
40
|
+
/** @type {VariableDeclarator} */
|
|
41
|
+
const declarator = {
|
|
42
|
+
type: 'VariableDeclarator',
|
|
43
|
+
id: importNamespaceSpecifier.local,
|
|
44
|
+
init
|
|
45
|
+
}
|
|
46
|
+
create(importNamespaceSpecifier, declarator)
|
|
47
|
+
declarations.push(declarator)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
declarations.push({
|
|
51
|
+
type: 'VariableDeclarator',
|
|
52
|
+
id: {
|
|
53
|
+
type: 'ObjectPattern',
|
|
54
|
+
properties: otherSpecifiers.map((specifier) => {
|
|
55
|
+
/** @type {Identifier} */
|
|
56
|
+
let key =
|
|
57
|
+
specifier.type === 'ImportSpecifier'
|
|
58
|
+
? specifier.imported
|
|
59
|
+
: specifier.type === 'ExportSpecifier'
|
|
60
|
+
? specifier.exported
|
|
61
|
+
: {type: 'Identifier', name: 'default'}
|
|
62
|
+
let value = specifier.local
|
|
63
|
+
|
|
64
|
+
// Switch them around if we’re exporting.
|
|
65
|
+
if (specifier.type === 'ExportSpecifier') {
|
|
66
|
+
value = key
|
|
67
|
+
key = specifier.local
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** @type {AssignmentProperty} */
|
|
71
|
+
const property = {
|
|
72
|
+
type: 'Property',
|
|
73
|
+
kind: 'init',
|
|
74
|
+
shorthand: key.name === value.name,
|
|
75
|
+
method: false,
|
|
76
|
+
computed: false,
|
|
77
|
+
key,
|
|
78
|
+
value
|
|
79
|
+
}
|
|
80
|
+
create(specifier, property)
|
|
81
|
+
return property
|
|
82
|
+
})
|
|
83
|
+
},
|
|
84
|
+
init: importNamespaceSpecifier
|
|
85
|
+
? {type: 'Identifier', name: importNamespaceSpecifier.local.name}
|
|
86
|
+
: init
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
return declarations
|
|
90
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('estree-jsx').Expression} Expression
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {Array<Expression>} expressions
|
|
7
|
+
*/
|
|
8
|
+
export function toBinaryAddition(expressions) {
|
|
9
|
+
let index = -1
|
|
10
|
+
/** @type {Expression | undefined} */
|
|
11
|
+
let left
|
|
12
|
+
|
|
13
|
+
while (++index < expressions.length) {
|
|
14
|
+
const right = expressions[index]
|
|
15
|
+
left = left ? {type: 'BinaryExpression', left, operator: '+', right} : right
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Just for types.
|
|
19
|
+
/* c8 ignore next */
|
|
20
|
+
if (!left) throw new Error('Expected non-empty `expressions` to be passed')
|
|
21
|
+
|
|
22
|
+
return left
|
|
23
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('estree-jsx').Identifier} Identifier
|
|
3
|
+
* @typedef {import('estree-jsx').JSXIdentifier} JSXIdentifier
|
|
4
|
+
* @typedef {import('estree-jsx').JSXMemberExpression} JSXMemberExpression
|
|
5
|
+
* @typedef {import('estree-jsx').Literal} Literal
|
|
6
|
+
* @typedef {import('estree-jsx').MemberExpression} MemberExpression
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
start as esStart,
|
|
11
|
+
cont as esCont,
|
|
12
|
+
name as isIdentifierName
|
|
13
|
+
} from 'estree-util-is-identifier-name'
|
|
14
|
+
|
|
15
|
+
export const toIdOrMemberExpression = toIdOrMemberExpressionFactory(
|
|
16
|
+
'Identifier',
|
|
17
|
+
'MemberExpression',
|
|
18
|
+
isIdentifierName
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
export const toJsxIdOrMemberExpression =
|
|
22
|
+
// @ts-expect-error: fine
|
|
23
|
+
/** @type {(ids: Array<string | number>) => JSXIdentifier | JSXMemberExpression)} */
|
|
24
|
+
(
|
|
25
|
+
toIdOrMemberExpressionFactory(
|
|
26
|
+
'JSXIdentifier',
|
|
27
|
+
'JSXMemberExpression',
|
|
28
|
+
isJsxIdentifierName
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {string} idType
|
|
34
|
+
* @param {string} memberType
|
|
35
|
+
* @param {(value: string) => boolean} isIdentifier
|
|
36
|
+
*/
|
|
37
|
+
function toIdOrMemberExpressionFactory(idType, memberType, isIdentifier) {
|
|
38
|
+
return toIdOrMemberExpression
|
|
39
|
+
/**
|
|
40
|
+
* @param {Array<string | number>} ids
|
|
41
|
+
* @returns {Identifier | MemberExpression}
|
|
42
|
+
*/
|
|
43
|
+
function toIdOrMemberExpression(ids) {
|
|
44
|
+
let index = -1
|
|
45
|
+
/** @type {Identifier | Literal | MemberExpression | undefined} */
|
|
46
|
+
let object
|
|
47
|
+
|
|
48
|
+
while (++index < ids.length) {
|
|
49
|
+
const name = ids[index]
|
|
50
|
+
const valid = typeof name === 'string' && isIdentifier(name)
|
|
51
|
+
|
|
52
|
+
// A value of `asd.123` could be turned into `asd['123']` in the JS form,
|
|
53
|
+
// but JSX does not have a form for it, so throw.
|
|
54
|
+
/* c8 ignore next 3 */
|
|
55
|
+
if (idType === 'JSXIdentifier' && !valid) {
|
|
56
|
+
throw new Error('Cannot turn `' + name + '` into a JSX identifier')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** @type {Identifier | Literal} */
|
|
60
|
+
// @ts-expect-error: JSX is fine.
|
|
61
|
+
const id = valid ? {type: idType, name} : {type: 'Literal', value: name}
|
|
62
|
+
// @ts-expect-error: JSX is fine.
|
|
63
|
+
object = object
|
|
64
|
+
? {
|
|
65
|
+
type: memberType,
|
|
66
|
+
object,
|
|
67
|
+
property: id,
|
|
68
|
+
computed: id.type === 'Literal',
|
|
69
|
+
optional: false
|
|
70
|
+
}
|
|
71
|
+
: id
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Just for types.
|
|
75
|
+
/* c8 ignore next 3 */
|
|
76
|
+
if (!object) throw new Error('Expected non-empty `ids` to be passed')
|
|
77
|
+
if (object.type === 'Literal')
|
|
78
|
+
throw new Error('Expected identifier as left-most value')
|
|
79
|
+
|
|
80
|
+
return object
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Checks if the given string is a valid JSX identifier name.
|
|
86
|
+
* @param {string} name
|
|
87
|
+
*/
|
|
88
|
+
function isJsxIdentifierName(name) {
|
|
89
|
+
let index = -1
|
|
90
|
+
|
|
91
|
+
while (++index < name.length) {
|
|
92
|
+
// We currently receive valid input, but this catches bugs and is needed
|
|
93
|
+
// when externalized.
|
|
94
|
+
/* c8 ignore next */
|
|
95
|
+
if (!(index ? jsxCont : esStart)(name.charCodeAt(index))) return false
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// `false` if `name` is empty.
|
|
99
|
+
return index > 0
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Checks if the given character code can continue a JSX identifier.
|
|
104
|
+
* @param {number} code
|
|
105
|
+
*/
|
|
106
|
+
function jsxCont(code) {
|
|
107
|
+
return code === 45 /* `-` */ || esCont(code)
|
|
108
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {SyntaxError} error
|
|
3
|
+
* @param {string} bg
|
|
4
|
+
* @param {string} color
|
|
5
|
+
* @returns {import('estree-jsx').Program}
|
|
6
|
+
*/
|
|
7
|
+
export default (error, bg = '#F44336', color = 'white') => {
|
|
8
|
+
return {
|
|
9
|
+
type: 'Program',
|
|
10
|
+
body: [
|
|
11
|
+
{
|
|
12
|
+
type: 'ExpressionStatement',
|
|
13
|
+
expression: {
|
|
14
|
+
type: 'JSXElement',
|
|
15
|
+
openingElement: {
|
|
16
|
+
type: 'JSXOpeningElement',
|
|
17
|
+
attributes: [
|
|
18
|
+
{
|
|
19
|
+
type: 'JSXAttribute',
|
|
20
|
+
name: {
|
|
21
|
+
type: 'JSXIdentifier',
|
|
22
|
+
name: 'style',
|
|
23
|
+
},
|
|
24
|
+
value: {
|
|
25
|
+
type: 'JSXExpressionContainer',
|
|
26
|
+
expression: {
|
|
27
|
+
type: 'ObjectExpression',
|
|
28
|
+
properties: [
|
|
29
|
+
{
|
|
30
|
+
type: 'Property',
|
|
31
|
+
method: false,
|
|
32
|
+
shorthand: false,
|
|
33
|
+
computed: false,
|
|
34
|
+
key: {
|
|
35
|
+
type: 'Identifier',
|
|
36
|
+
name: 'backgroundColor',
|
|
37
|
+
},
|
|
38
|
+
value: {
|
|
39
|
+
type: 'Literal',
|
|
40
|
+
value: bg,
|
|
41
|
+
raw: `'${bg}'`,
|
|
42
|
+
},
|
|
43
|
+
kind: 'init',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: 'Property',
|
|
47
|
+
method: false,
|
|
48
|
+
shorthand: false,
|
|
49
|
+
computed: false,
|
|
50
|
+
key: {
|
|
51
|
+
type: 'Identifier',
|
|
52
|
+
name: 'color',
|
|
53
|
+
},
|
|
54
|
+
value: {
|
|
55
|
+
type: 'Literal',
|
|
56
|
+
value: color,
|
|
57
|
+
raw: `'${color}'`,
|
|
58
|
+
},
|
|
59
|
+
kind: 'init',
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
name: {
|
|
67
|
+
type: 'JSXIdentifier',
|
|
68
|
+
name: 'pre',
|
|
69
|
+
},
|
|
70
|
+
selfClosing: false,
|
|
71
|
+
},
|
|
72
|
+
closingElement: {
|
|
73
|
+
type: 'JSXClosingElement',
|
|
74
|
+
name: {
|
|
75
|
+
type: 'JSXIdentifier',
|
|
76
|
+
name: 'pre',
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
children: [
|
|
80
|
+
{
|
|
81
|
+
type: 'JSXText',
|
|
82
|
+
value: error.message,
|
|
83
|
+
raw: error.message,
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
sourceType: 'module',
|
|
90
|
+
}
|
|
91
|
+
}
|