unframer 2.7.6 → 2.7.7
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 +0 -5
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +7 -31
- package/dist/cli.js.map +1 -1
- package/dist/esbuild.d.ts +7 -0
- package/dist/esbuild.d.ts.map +1 -1
- package/dist/esbuild.js +15 -1
- package/dist/esbuild.js.map +1 -1
- package/dist/exporter.d.ts +6 -14
- package/dist/exporter.d.ts.map +1 -1
- package/dist/exporter.js +24 -9
- package/dist/exporter.js.map +1 -1
- package/dist/exporter.test.js +48 -0
- package/dist/exporter.test.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/unframer-loader.d.ts.map +1 -1
- package/dist/unframer-loader.js +4 -3
- package/dist/unframer-loader.js.map +1 -1
- package/esm/cli.d.ts +14 -0
- package/esm/cli.d.ts.map +1 -1
- package/esm/cli.js +7 -31
- package/esm/cli.js.map +1 -1
- package/esm/esbuild.d.ts +7 -0
- package/esm/esbuild.d.ts.map +1 -1
- package/esm/esbuild.js +13 -0
- package/esm/esbuild.js.map +1 -1
- package/esm/exporter.d.ts +6 -14
- package/esm/exporter.d.ts.map +1 -1
- package/esm/exporter.js +25 -10
- package/esm/exporter.js.map +1 -1
- package/esm/exporter.test.js +48 -0
- package/esm/exporter.test.js.map +1 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js.map +1 -1
- package/esm/unframer-loader.d.ts.map +1 -1
- package/esm/unframer-loader.js +4 -3
- package/esm/unframer-loader.js.map +1 -1
- package/package.json +2 -1
- package/src/cli.tsx +9 -40
- package/src/esbuild.ts +24 -2
- package/src/exporter.test.ts +66 -0
- package/src/exporter.ts +33 -14
- package/src/index.ts +2 -0
- package/src/unframer-loader.ts +7 -3
package/src/cli.tsx
CHANGED
|
@@ -40,7 +40,9 @@ cli.command('[projectId]', 'Run unframer with optional project ID')
|
|
|
40
40
|
return
|
|
41
41
|
}
|
|
42
42
|
const data = await response.json()
|
|
43
|
-
|
|
43
|
+
logger.log('unframer data', data)
|
|
44
|
+
let cwd = path.resolve(process.cwd(), outDir || 'framer')
|
|
45
|
+
return await bundle({
|
|
44
46
|
config: {
|
|
45
47
|
outDir,
|
|
46
48
|
components: Object.fromEntries(
|
|
@@ -50,10 +52,11 @@ cli.command('[projectId]', 'Run unframer with optional project ID')
|
|
|
50
52
|
]),
|
|
51
53
|
),
|
|
52
54
|
tokens: data.colorStyles,
|
|
55
|
+
framerWebPages: data.framerWebPages || [],
|
|
53
56
|
},
|
|
54
57
|
watch: false,
|
|
55
58
|
|
|
56
|
-
|
|
59
|
+
cwd,
|
|
57
60
|
signal: new AbortController().signal,
|
|
58
61
|
})
|
|
59
62
|
}
|
|
@@ -79,11 +82,11 @@ cli.command('[projectId]', 'Run unframer with optional project ID')
|
|
|
79
82
|
|
|
80
83
|
let controller = new AbortController()
|
|
81
84
|
setMaxListeners(0, controller.signal)
|
|
82
|
-
|
|
85
|
+
await bundle({
|
|
83
86
|
config,
|
|
84
87
|
watch: false,
|
|
85
88
|
signal: controller.signal,
|
|
86
|
-
|
|
89
|
+
cwd: path.resolve(process.cwd(), outDir || 'framer'),
|
|
87
90
|
})
|
|
88
91
|
})
|
|
89
92
|
|
|
@@ -154,46 +157,12 @@ function getNewNames(oldConfig: Config, newConfig: Config) {
|
|
|
154
157
|
return newNames
|
|
155
158
|
}
|
|
156
159
|
|
|
157
|
-
type Config = {
|
|
160
|
+
export type Config = {
|
|
158
161
|
components: {
|
|
159
162
|
[name: string]: string
|
|
160
163
|
}
|
|
164
|
+
framerWebPages?: { webPageId: string; path: string }[]
|
|
161
165
|
breakpoints?: BreakpointSizes
|
|
162
166
|
tokens?: StyleToken[]
|
|
163
167
|
outDir?: string
|
|
164
168
|
}
|
|
165
|
-
async function processConfig({
|
|
166
|
-
config,
|
|
167
|
-
watch,
|
|
168
|
-
signal,
|
|
169
|
-
configBasename,
|
|
170
|
-
}: {
|
|
171
|
-
config: Config
|
|
172
|
-
watch: boolean
|
|
173
|
-
configBasename: string
|
|
174
|
-
signal?: AbortSignal
|
|
175
|
-
}) {
|
|
176
|
-
try {
|
|
177
|
-
const { components, breakpoints, outDir } = config || {}
|
|
178
|
-
const installDir = path.resolve(process.cwd(), outDir || 'framer')
|
|
179
|
-
if (!components) {
|
|
180
|
-
logger.log(`No components found in ${configBasename}`)
|
|
181
|
-
return
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
await bundle({
|
|
185
|
-
components,
|
|
186
|
-
breakpoints,
|
|
187
|
-
cwd: installDir,
|
|
188
|
-
watch,
|
|
189
|
-
tokens: config.tokens,
|
|
190
|
-
signal,
|
|
191
|
-
})
|
|
192
|
-
} catch (e: any) {
|
|
193
|
-
if (signal) {
|
|
194
|
-
logger.log('Error processing config', e.stack)
|
|
195
|
-
return
|
|
196
|
-
}
|
|
197
|
-
throw e
|
|
198
|
-
}
|
|
199
|
-
}
|
package/src/esbuild.ts
CHANGED
|
@@ -12,6 +12,28 @@ export const externalPackages = [
|
|
|
12
12
|
]
|
|
13
13
|
|
|
14
14
|
let redirectCache = new Map<string, Promise<string>>()
|
|
15
|
+
|
|
16
|
+
export const replaceWebPageIds = ({
|
|
17
|
+
elements,
|
|
18
|
+
code,
|
|
19
|
+
}: {
|
|
20
|
+
elements: { webPageId: string; path: string }[]
|
|
21
|
+
code: string
|
|
22
|
+
}) => {
|
|
23
|
+
// Match webPageId pattern with optional trailing comma
|
|
24
|
+
const pattern = /{[\s\n]*webPageId[\s\n]*:[\s\n]*(['"])(.*?)\1[\s\n]*,?[\s\n]*}/g
|
|
25
|
+
|
|
26
|
+
return code.replace(pattern, (match, quote, id) => {
|
|
27
|
+
const path = elements.find((e) => e.webPageId === id)?.path
|
|
28
|
+
if (!path) {
|
|
29
|
+
return match
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
logger.log(`Replacing relative link to ${id} with fixed path: ${path}`)
|
|
33
|
+
return `'${path}'`
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
15
37
|
export function esbuildPluginBundleDependencies({
|
|
16
38
|
signal = undefined as AbortSignal | undefined,
|
|
17
39
|
externalizeNpm = false,
|
|
@@ -96,7 +118,7 @@ export function esbuildPluginBundleDependencies({
|
|
|
96
118
|
build.onEnd(() => {
|
|
97
119
|
spinner.stop()
|
|
98
120
|
})
|
|
99
|
-
|
|
121
|
+
|
|
100
122
|
build.onLoad({ filter: /.*/, namespace }, async (args) => {
|
|
101
123
|
if (signal?.aborted) {
|
|
102
124
|
throw new Error('aborted')
|
|
@@ -119,7 +141,7 @@ export function esbuildPluginBundleDependencies({
|
|
|
119
141
|
const promise = Promise.resolve().then(async () => {
|
|
120
142
|
logger.log('fetching', url.replace(/https?:\/\//, ''))
|
|
121
143
|
spinner.update(`Fetching ${url.replace(/https?:\/\//, '')}`)
|
|
122
|
-
|
|
144
|
+
|
|
123
145
|
const res = await fetchWithRetry(resolved, { signal })
|
|
124
146
|
if (!res.ok) {
|
|
125
147
|
throw new Error(
|
package/src/exporter.test.ts
CHANGED
|
@@ -1,5 +1,71 @@
|
|
|
1
1
|
import { describe, test, expect } from 'vitest'
|
|
2
2
|
import { propCamelCase } from './exporter'
|
|
3
|
+
import { replaceWebPageIds } from './esbuild'
|
|
4
|
+
|
|
5
|
+
describe('replaceWebPageIds', () => {
|
|
6
|
+
test('replaces webPageIds with paths', () => {
|
|
7
|
+
const elements = [
|
|
8
|
+
{ webPageId: 'abc123', path: '/page1' },
|
|
9
|
+
{ webPageId: 'def456', path: '/page2' },
|
|
10
|
+
]
|
|
11
|
+
const code = `{ webPageId: 'abc123' }`
|
|
12
|
+
expect(replaceWebPageIds({ elements, code })).toEqual(`'/page1'`)
|
|
13
|
+
|
|
14
|
+
const code2 = `{ webPageId: "def456" }`
|
|
15
|
+
expect(replaceWebPageIds({ elements, code: code2 })).toEqual(`'/page2'`)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('handles whitespace variations', () => {
|
|
19
|
+
const elements = [{ webPageId: 'abc123', path: '/page1' }]
|
|
20
|
+
|
|
21
|
+
const code = `{webPageId:'abc123'}`
|
|
22
|
+
expect(replaceWebPageIds({ elements, code })).toEqual(`'/page1'`)
|
|
23
|
+
|
|
24
|
+
const code2 = `{ webPageId : 'abc123' }`
|
|
25
|
+
expect(replaceWebPageIds({ elements, code: code2 })).toEqual(`'/page1'`)
|
|
26
|
+
const code3 = `{ href: { webPageId: 'zRPFqFbvc' } }`
|
|
27
|
+
expect(
|
|
28
|
+
replaceWebPageIds({
|
|
29
|
+
elements: [{ webPageId: 'zRPFqFbvc', path: '/page1' }],
|
|
30
|
+
code: code3,
|
|
31
|
+
}),
|
|
32
|
+
).toEqual(`{ href: '/page1' }`)
|
|
33
|
+
const code4 = `/* @__PURE__ */ _jsx(Link, {
|
|
34
|
+
href: { webPageId: 'zRPFqFbvc', },
|
|
35
|
+
nodeId: 'aU2SMIi6t',`
|
|
36
|
+
expect(
|
|
37
|
+
replaceWebPageIds({
|
|
38
|
+
elements: [{ webPageId: 'zRPFqFbvc', path: '/page1' }],
|
|
39
|
+
code: code4,
|
|
40
|
+
}),
|
|
41
|
+
).toMatchInlineSnapshot(
|
|
42
|
+
`
|
|
43
|
+
"/* @__PURE__ */ _jsx(Link, {
|
|
44
|
+
href: '/page1',
|
|
45
|
+
nodeId: 'aU2SMIi6t',"
|
|
46
|
+
`,
|
|
47
|
+
)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('preserves non-matching webPageIds', () => {
|
|
51
|
+
const elements = [{ webPageId: 'abc123', path: '/page1' }]
|
|
52
|
+
const code = `{ webPageId: 'xyz789' }`
|
|
53
|
+
|
|
54
|
+
expect(replaceWebPageIds({ elements, code })).toEqual(
|
|
55
|
+
`{ webPageId: 'xyz789' }`,
|
|
56
|
+
)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('handles newlines in input', () => {
|
|
60
|
+
const elements = [{ webPageId: 'abc123', path: '/page1' }]
|
|
61
|
+
|
|
62
|
+
const code = `{\n webPageId: 'abc123'\n}`
|
|
63
|
+
expect(replaceWebPageIds({ elements, code })).toEqual(`'/page1'`)
|
|
64
|
+
|
|
65
|
+
const code2 = `{\n\n webPageId:\n 'abc123'\n\n}`
|
|
66
|
+
expect(replaceWebPageIds({ elements, code: code2 })).toEqual(`'/page1'`)
|
|
67
|
+
})
|
|
68
|
+
})
|
|
3
69
|
|
|
4
70
|
describe('propCamelCase', () => {
|
|
5
71
|
test('converts dashes to camelCase', () => {
|
package/src/exporter.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BuildResult, context } from 'esbuild'
|
|
2
|
+
import { Config } from './cli'
|
|
2
3
|
import url from 'url'
|
|
3
4
|
|
|
4
5
|
import { Sema } from 'async-sema'
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
import {
|
|
22
23
|
esbuildPluginBundleDependencies,
|
|
23
24
|
externalPackages,
|
|
25
|
+
replaceWebPageIds,
|
|
24
26
|
resolveRedirect,
|
|
25
27
|
} from './esbuild'
|
|
26
28
|
import {
|
|
@@ -47,13 +49,17 @@ export type StyleToken = {
|
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
export async function bundle({
|
|
52
|
+
config,
|
|
50
53
|
cwd: out = '',
|
|
51
54
|
watch = false,
|
|
52
|
-
components = {} as Record<string, string>,
|
|
53
|
-
tokens = [] as StyleToken[],
|
|
54
|
-
breakpoints = {} as BreakpointSizes,
|
|
55
55
|
signal = undefined as AbortSignal | undefined,
|
|
56
|
+
}: {
|
|
57
|
+
config: Config
|
|
58
|
+
cwd: string
|
|
59
|
+
watch?: boolean
|
|
60
|
+
signal?: AbortSignal
|
|
56
61
|
}) {
|
|
62
|
+
const { components, breakpoints, tokens, outDir, framerWebPages } = config
|
|
57
63
|
out ||= path.resolve(process.cwd(), 'example')
|
|
58
64
|
out = path.resolve(out)
|
|
59
65
|
try {
|
|
@@ -156,6 +162,12 @@ export async function bundle({
|
|
|
156
162
|
trailingCommas: 'always',
|
|
157
163
|
semiColons: 'always',
|
|
158
164
|
})
|
|
165
|
+
if (framerWebPages?.length) {
|
|
166
|
+
codeNew = replaceWebPageIds({
|
|
167
|
+
code: codeNew,
|
|
168
|
+
elements: framerWebPages,
|
|
169
|
+
})
|
|
170
|
+
}
|
|
159
171
|
const lines = findRelativeLinks(codeNew)
|
|
160
172
|
if (lines.length) {
|
|
161
173
|
spinner.error(
|
|
@@ -236,7 +248,7 @@ export async function bundle({
|
|
|
236
248
|
'/* This file was generated by Unframer, do not edit manually */\n' +
|
|
237
249
|
'/* This css file has all the necessary styles to run all your components */\n' +
|
|
238
250
|
'\n' +
|
|
239
|
-
getStyleTokensCss(tokens) +
|
|
251
|
+
getStyleTokensCss(tokens || []) +
|
|
240
252
|
breakpointsStyles(breakpoints) +
|
|
241
253
|
'\n\n' +
|
|
242
254
|
combinedCSSRules
|
|
@@ -663,10 +675,6 @@ function getTokensCss({
|
|
|
663
675
|
|
|
664
676
|
const nodePath = process.argv[0] || 'node'
|
|
665
677
|
|
|
666
|
-
let UNFRAMER_RUNTIME_PATH = url.pathToFileURL(
|
|
667
|
-
require.resolve('../esm/index.js'),
|
|
668
|
-
).href
|
|
669
|
-
|
|
670
678
|
export async function extractPropControlsUnsafe(
|
|
671
679
|
filename,
|
|
672
680
|
name,
|
|
@@ -685,6 +693,11 @@ export async function extractPropControlsUnsafe(
|
|
|
685
693
|
)}); console.log(${propCode}) })`
|
|
686
694
|
|
|
687
695
|
const TIMEOUT = 5 * 1000
|
|
696
|
+
const UNFRAMER_MAP_PACKAGES = JSON.stringify({
|
|
697
|
+
unframer: url.pathToFileURL(require.resolve('../esm/index.js')).href,
|
|
698
|
+
react: url.pathToFileURL(require.resolve('react')).href,
|
|
699
|
+
'react-dom': url.pathToFileURL(require.resolve('react-dom')).href,
|
|
700
|
+
})
|
|
688
701
|
let stdout = await new Promise<string>((res, rej) => {
|
|
689
702
|
let childProcess = exec(
|
|
690
703
|
`${JSON.stringify(
|
|
@@ -695,14 +708,17 @@ export async function extractPropControlsUnsafe(
|
|
|
695
708
|
{
|
|
696
709
|
env: {
|
|
697
710
|
// ...process.env,
|
|
698
|
-
|
|
711
|
+
UNFRAMER_MAP_PACKAGES,
|
|
699
712
|
},
|
|
700
713
|
},
|
|
701
|
-
(err, stdout) => {
|
|
714
|
+
(err, stdout, stderr) => {
|
|
702
715
|
clearTimeout(timer)
|
|
703
716
|
if (err) {
|
|
717
|
+
spinner.error(`error extracting types for ${name}`)
|
|
718
|
+
spinner.error(stderr)
|
|
704
719
|
return rej(err)
|
|
705
720
|
}
|
|
721
|
+
|
|
706
722
|
res(stdout)
|
|
707
723
|
},
|
|
708
724
|
)
|
|
@@ -716,12 +732,15 @@ export async function extractPropControlsUnsafe(
|
|
|
716
732
|
)
|
|
717
733
|
}, TIMEOUT)
|
|
718
734
|
}).catch((e) => {
|
|
719
|
-
spinner.error(`error extracting types for ${name}`)
|
|
720
735
|
logger.log(e.stack)
|
|
721
|
-
|
|
736
|
+
return ''
|
|
722
737
|
})
|
|
723
738
|
|
|
724
|
-
stdout = stdout.split(delimiter)[1]
|
|
739
|
+
stdout = stdout.split(delimiter)[1] || ''
|
|
740
|
+
if (!stdout) {
|
|
741
|
+
return {}
|
|
742
|
+
}
|
|
743
|
+
|
|
725
744
|
// console.log(stdout)
|
|
726
745
|
return safeJsonParse(stdout)
|
|
727
746
|
}
|
|
@@ -1000,7 +1019,7 @@ export function propCamelCase(str: string) {
|
|
|
1000
1019
|
}
|
|
1001
1020
|
// Convert dashes to camelCase (e.g. foo-bar -> fooBar)
|
|
1002
1021
|
str = str.replace(/-([\w])/g, (g) => g[1].toUpperCase())
|
|
1003
|
-
// Convert underscores to camelCase (e.g. foo_bar -> fooBar)
|
|
1022
|
+
// Convert underscores to camelCase (e.g. foo_bar -> fooBar)
|
|
1004
1023
|
str = str.replace(/_([a-z])/g, (g) => g[1].toUpperCase())
|
|
1005
1024
|
// Remove spaces (e.g. "Foo Bar" -> "fooBar")
|
|
1006
1025
|
str = str.replace(/\s+(.)/g, (_, c) => c.toUpperCase())
|
package/src/index.ts
CHANGED
package/src/unframer-loader.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
const mapPackages = JSON.parse(process.env.UNFRAMER_MAP_PACKAGES || '{}')
|
|
2
|
+
|
|
1
3
|
export async function resolve(specifier, context, defaultResolve) {
|
|
2
|
-
if (specifier
|
|
4
|
+
if (mapPackages[specifier]) {
|
|
3
5
|
return {
|
|
4
|
-
url:
|
|
5
|
-
format: 'module', // Specify that unframer is an ES module
|
|
6
|
+
url: mapPackages[specifier],
|
|
7
|
+
// format: 'module', // Specify that unframer is an ES module
|
|
6
8
|
shortCircuit: true, // Signal that we're intentionally not calling next hook
|
|
7
9
|
}
|
|
8
10
|
}
|
|
11
|
+
|
|
12
|
+
|
|
9
13
|
return defaultResolve(specifier, context, defaultResolve)
|
|
10
14
|
}
|