unframer 2.7.7 → 2.7.8

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.
Files changed (48) hide show
  1. package/README.md +5 -1
  2. package/dist/babel-plugin-imports.d.ts +21 -0
  3. package/dist/babel-plugin-imports.d.ts.map +1 -0
  4. package/dist/babel-plugin-imports.js +375 -0
  5. package/dist/babel-plugin-imports.js.map +1 -0
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +2 -11
  8. package/dist/cli.js.map +1 -1
  9. package/dist/css.d.ts.map +1 -1
  10. package/dist/css.js +4 -3
  11. package/dist/css.js.map +1 -1
  12. package/dist/exporter.d.ts.map +1 -1
  13. package/dist/exporter.js +55 -29
  14. package/dist/exporter.js.map +1 -1
  15. package/dist/framer.d.ts.map +1 -1
  16. package/dist/framer.js +26 -1788
  17. package/dist/framer.js.map +1 -1
  18. package/dist/renamer.d.ts +12 -0
  19. package/dist/renamer.d.ts.map +1 -0
  20. package/dist/renamer.js +169 -0
  21. package/dist/renamer.js.map +1 -0
  22. package/esm/babel-plugin-imports.d.ts +21 -0
  23. package/esm/babel-plugin-imports.d.ts.map +1 -0
  24. package/esm/babel-plugin-imports.js +344 -0
  25. package/esm/babel-plugin-imports.js.map +1 -0
  26. package/esm/cli.d.ts.map +1 -1
  27. package/esm/cli.js +2 -11
  28. package/esm/cli.js.map +1 -1
  29. package/esm/css.d.ts.map +1 -1
  30. package/esm/css.js +3 -2
  31. package/esm/css.js.map +1 -1
  32. package/esm/exporter.d.ts.map +1 -1
  33. package/esm/exporter.js +53 -27
  34. package/esm/exporter.js.map +1 -1
  35. package/esm/framer.d.ts.map +1 -1
  36. package/esm/framer.js +27 -1788
  37. package/esm/framer.js.map +1 -1
  38. package/esm/renamer.d.ts +12 -0
  39. package/esm/renamer.d.ts.map +1 -0
  40. package/esm/renamer.js +140 -0
  41. package/esm/renamer.js.map +1 -0
  42. package/package.json +5 -4
  43. package/src/babel-plugin-imports.ts +441 -0
  44. package/src/cli.tsx +2 -12
  45. package/src/css.ts +3 -2
  46. package/src/exporter.ts +62 -28
  47. package/src/framer.js +25 -1827
  48. package/src/renamer.ts +184 -0
@@ -0,0 +1,12 @@
1
+ import type { Scope } from '@babel/traverse';
2
+ import * as t from '@babel/types';
3
+ import { NodePath } from '@babel/core';
4
+ export default class BatchRenamer {
5
+ constructor(scope: Scope, map: Map<string, string>);
6
+ map: Map<string, string>;
7
+ scope: Scope;
8
+ maybeConvertFromExportDeclaration(parentDeclar: NodePath): void;
9
+ maybeConvertFromClassFunctionExpression(path: NodePath): NodePath<t.Node>;
10
+ rename(): void;
11
+ }
12
+ //# sourceMappingURL=renamer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renamer.d.ts","sourceRoot":"","sources":["../src/renamer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAI5C,OAAO,KAAK,CAAC,MAAM,cAAc,CAAA;AAEjC,OAAO,EAAE,QAAQ,EAAW,MAAM,aAAa,CAAA;AAgF/C,MAAM,CAAC,OAAO,OAAO,YAAY;gBACjB,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAK1C,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAExB,KAAK,EAAE,KAAK,CAAA;IAEpB,iCAAiC,CAAC,YAAY,EAAE,QAAQ;IAyBxD,uCAAuC,CAAC,IAAI,EAAE,QAAQ;IAItD,MAAM;CAwDT"}
package/esm/renamer.js ADDED
@@ -0,0 +1,140 @@
1
+ // original https://github.com/babel/babel/blob/9c77558234c87b9220604fbc1519089e2d6334e2/packages/babel-traverse/src/scope/lib/renamer.ts#L61
2
+ import splitExportDeclaration from '@babel/helper-split-export-declaration';
3
+ import { visitors } from '@babel/traverse';
4
+ import { traverseNode } from '@babel/traverse/lib/traverse-node';
5
+ import * as t from '@babel/types';
6
+ import { logger } from './utils';
7
+ const renameVisitor = {
8
+ ReferencedIdentifier({ node }, state) {
9
+ for (let [oldName, newName] of state.map) {
10
+ // console.log(node.name, oldName, newName)
11
+ if (node.name === oldName) {
12
+ node.name = newName;
13
+ }
14
+ }
15
+ },
16
+ // Scope(path, state) {
17
+ // if (
18
+ // !path.scope.bindingIdentifierEquals(
19
+ // state.oldName,
20
+ // state.binding.identifier,
21
+ // )
22
+ // ) {
23
+ // path.skip()
24
+ // if (path.isMethod()) {
25
+ // requeueComputedKeyAndDecorators(path)
26
+ // }
27
+ // }
28
+ // },
29
+ ObjectProperty({ node, scope }, state) {
30
+ var _a;
31
+ const { name } = node.key;
32
+ if (node.shorthand &&
33
+ // In destructuring the identifier is already renamed by the
34
+ // AssignmentExpression|Declaration|VariableDeclarator visitor,
35
+ // while in object literals it's renamed later by the
36
+ // ReferencedIdentifier visitor.
37
+ // (name === state.oldName || name === state.newName) &&
38
+ (state.map.has(name) || inverseMap(state.map).has(name)) &&
39
+ // Ignore shadowed bindings
40
+ [...state.map.keys()].some((oldName) => state.scope.getBindingIdentifier(oldName) ===
41
+ scope.getBindingIdentifier(name))) {
42
+ node.shorthand = false;
43
+ if ((_a = node.extra) === null || _a === void 0 ? void 0 : _a.shorthand)
44
+ node.extra.shorthand = false;
45
+ }
46
+ },
47
+ // @ts-ignore
48
+ 'AssignmentExpression|Declaration|VariableDeclarator'(path, state) {
49
+ if (path.isVariableDeclaration())
50
+ return;
51
+ const ids = path.getOuterBindingIdentifiers();
52
+ for (const name in ids) {
53
+ for (let [oldName, newName] of state.map) {
54
+ // console.log(name, oldName, newName)
55
+ if (name === oldName)
56
+ ids[name].name = newName;
57
+ }
58
+ }
59
+ },
60
+ };
61
+ let cache = new WeakMap();
62
+ function inverseMap(map) {
63
+ if (cache.has(map))
64
+ return cache.get(map);
65
+ const inverse = new Map();
66
+ for (let [key, value] of map) {
67
+ inverse.set(value, key);
68
+ }
69
+ cache.set(map, inverse);
70
+ return inverse;
71
+ }
72
+ export default class BatchRenamer {
73
+ constructor(scope, map) {
74
+ this.map = map;
75
+ this.scope = scope;
76
+ }
77
+ maybeConvertFromExportDeclaration(parentDeclar) {
78
+ const maybeExportDeclar = parentDeclar.parentPath;
79
+ if (!(maybeExportDeclar === null || maybeExportDeclar === void 0 ? void 0 : maybeExportDeclar.isExportDeclaration())) {
80
+ return;
81
+ }
82
+ if (maybeExportDeclar.isExportDefaultDeclaration()) {
83
+ const { declaration } = maybeExportDeclar.node;
84
+ if (t.isDeclaration(declaration) && !declaration.id) {
85
+ return;
86
+ }
87
+ }
88
+ if (maybeExportDeclar.isExportAllDeclaration()) {
89
+ return;
90
+ }
91
+ splitExportDeclaration(maybeExportDeclar);
92
+ }
93
+ maybeConvertFromClassFunctionExpression(path) {
94
+ return path;
95
+ }
96
+ rename( /* Babel 7 - block?: t.Pattern | t.Scopable */) {
97
+ const { scope, map } = this;
98
+ for (let binding of [...map.keys()].map((name) => scope.getBinding(name))) {
99
+ if (!binding) {
100
+ continue;
101
+ }
102
+ const path = binding.path;
103
+ const parentDeclar = path.find((path) => path.isDeclaration() ||
104
+ path.isFunctionExpression() ||
105
+ path.isClassExpression());
106
+ if (parentDeclar) {
107
+ const bindingIds = parentDeclar.getOuterBindingIdentifiers();
108
+ const oldNames = Object.keys(bindingIds);
109
+ for (let oldName of oldNames) {
110
+ const binding = scope.getBinding(oldName);
111
+ if (binding && bindingIds[oldName] === binding.identifier) {
112
+ // When we are renaming an exported identifier, we need to ensure that
113
+ // the exported binding keeps the old name.
114
+ this.maybeConvertFromExportDeclaration(parentDeclar);
115
+ }
116
+ }
117
+ }
118
+ }
119
+ traverseNode(scope.block, visitors.explode(renameVisitor), scope, this, scope.path,
120
+ // When blockToTraverse is a SwitchStatement, the discriminant
121
+ // is not part of the current scope and thus should be skipped.
122
+ { discriminant: true });
123
+ for (let [oldName, newName] of map) {
124
+ if (oldName === newName)
125
+ continue;
126
+ if (!arguments[0]) {
127
+ scope.removeOwnBinding(oldName);
128
+ const binding = scope.getBinding(oldName);
129
+ if (binding) {
130
+ binding.identifier.name = newName;
131
+ scope.bindings[newName] = binding;
132
+ }
133
+ else {
134
+ logger.log(`binding not found for ${oldName}`);
135
+ }
136
+ }
137
+ }
138
+ }
139
+ }
140
+ //# sourceMappingURL=renamer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renamer.js","sourceRoot":"","sources":["../src/renamer.ts"],"names":[],"mappings":"AAAA,6IAA6I;AAC7I,OAAO,sBAAsB,MAAM,wCAAwC,CAAA;AAE3E,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAA;AAEhE,OAAO,KAAK,CAAC,MAAM,cAAc,CAAA;AAIjC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAEhC,MAAM,aAAa,GAA0B;IACzC,oBAAoB,CAAC,EAAE,IAAI,EAAE,EAAE,KAAK;QAChC,KAAK,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;YACvC,2CAA2C;YAC3C,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBACxB,IAAI,CAAC,IAAI,GAAG,OAAO,CAAA;YACvB,CAAC;QACL,CAAC;IACL,CAAC;IAED,uBAAuB;IACvB,WAAW;IACX,+CAA+C;IAC/C,6BAA6B;IAC7B,wCAAwC;IACxC,YAAY;IACZ,UAAU;IACV,sBAAsB;IACtB,iCAAiC;IACjC,oDAAoD;IACpD,YAAY;IACZ,QAAQ;IACR,KAAK;IAEL,cAAc,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK;;QACjC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,GAAiB,CAAA;QACvC,IACI,IAAI,CAAC,SAAS;YACd,4DAA4D;YAC5D,+DAA+D;YAC/D,qDAAqD;YACrD,gCAAgC;YAChC,wDAAwD;YACxD,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACxD,2BAA2B;YAC3B,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CACtB,CAAC,OAAO,EAAE,EAAE,CACR,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,OAAO,CAAC;gBACzC,KAAK,CAAC,oBAAoB,CAAC,IAAI,CAAC,CACvC,EACH,CAAC;YACC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAA;YACtB,IAAI,MAAA,IAAI,CAAC,KAAK,0CAAE,SAAS;gBAAE,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,KAAK,CAAA;QAC3D,CAAC;IACL,CAAC;IAED,aAAa;IACb,qDAAqD,CACjD,IAEC,EACD,KAAK;QAEL,IAAI,IAAI,CAAC,qBAAqB,EAAE;YAAE,OAAM;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,0BAA0B,EAAE,CAAA;QAE7C,KAAK,MAAM,IAAI,IAAI,GAAG,EAAE,CAAC;YACrB,KAAK,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;gBACvC,sCAAsC;gBACtC,IAAI,IAAI,KAAK,OAAO;oBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,OAAO,CAAA;YAClD,CAAC;QACL,CAAC;IACL,CAAC;CACJ,CAAA;AAED,IAAI,KAAK,GAAG,IAAI,OAAO,EAAE,CAAA;AACzB,SAAS,UAAU,CAAC,GAAwB;IACxC,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACzC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAE,CAAA;IACzB,KAAK,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IAC3B,CAAC;IACD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IACvB,OAAO,OAAO,CAAA;AAClB,CAAC;AAED,MAAM,CAAC,OAAO,OAAO,YAAY;IAC7B,YAAY,KAAY,EAAE,GAAwB;QAC9C,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;QACd,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IACtB,CAAC;IAMD,iCAAiC,CAAC,YAAsB;QACpD,MAAM,iBAAiB,GAAG,YAAY,CAAC,UAAU,CAAA;QAEjD,IAAI,CAAC,CAAA,iBAAiB,aAAjB,iBAAiB,uBAAjB,iBAAiB,CAAE,mBAAmB,EAAE,CAAA,EAAE,CAAC;YAC5C,OAAM;QACV,CAAC;QAED,IAAI,iBAAiB,CAAC,0BAA0B,EAAE,EAAE,CAAC;YACjD,MAAM,EAAE,WAAW,EAAE,GAAG,iBAAiB,CAAC,IAAI,CAAA;YAC9C,IAAI,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC;gBAClD,OAAM;YACV,CAAC;QACL,CAAC;QAED,IAAI,iBAAiB,CAAC,sBAAsB,EAAE,EAAE,CAAC;YAC7C,OAAM;QACV,CAAC;QAED,sBAAsB,CAClB,iBAEC,CACJ,CAAA;IACL,CAAC;IAED,uCAAuC,CAAC,IAAc;QAClD,OAAO,IAAI,CAAA;IACf,CAAC;IAED,MAAM,EAAC,8CAA8C;QACjD,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;QAE3B,KAAK,IAAI,OAAO,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAC7C,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CACzB,EAAE,CAAC;YACA,IAAI,CAAC,OAAO,EAAE,CAAC;gBACX,SAAQ;YACZ,CAAC;YACD,MAAM,IAAI,GAAG,OAAQ,CAAC,IAAI,CAAA;YAC1B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAC1B,CAAC,IAAI,EAAE,EAAE,CACL,IAAI,CAAC,aAAa,EAAE;gBACpB,IAAI,CAAC,oBAAoB,EAAE;gBAC3B,IAAI,CAAC,iBAAiB,EAAE,CAC/B,CAAA;YACD,IAAI,YAAY,EAAE,CAAC;gBACf,MAAM,UAAU,GAAG,YAAY,CAAC,0BAA0B,EAAE,CAAA;gBAC5D,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;gBACxC,KAAK,IAAI,OAAO,IAAI,QAAQ,EAAE,CAAC;oBAC3B,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;oBACzC,IAAI,OAAO,IAAI,UAAU,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC;wBACxD,sEAAsE;wBACtE,2CAA2C;wBAC3C,IAAI,CAAC,iCAAiC,CAAC,YAAY,CAAC,CAAA;oBACxD,CAAC;gBACL,CAAC;YACL,CAAC;QACL,CAAC;QAED,YAAY,CACR,KAAK,CAAC,KAAK,EACX,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,EAC/B,KAAK,EACL,IAAI,EACJ,KAAK,CAAC,IAAI;QACV,8DAA8D;QAC9D,+DAA+D;QAC/D,EAAE,YAAY,EAAE,IAAI,EAAE,CACzB,CAAA;QAED,KAAK,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,GAAG,EAAE,CAAC;YACjC,IAAI,OAAO,KAAK,OAAO;gBAAE,SAAQ;YAEjC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChB,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAA;gBAC/B,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;gBACzC,IAAI,OAAO,EAAE,CAAC;oBACV,OAAO,CAAC,UAAU,CAAC,IAAI,GAAG,OAAO,CAAA;oBACjC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;gBACrC,CAAC;qBAAM,CAAC;oBACJ,MAAM,CAAC,GAAG,CAAC,yBAAyB,OAAO,EAAE,CAAC,CAAA;gBAClD,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;CACJ"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unframer",
3
- "version": "2.7.7",
3
+ "version": "2.7.8",
4
4
  "description": "Import Framer components directly in your React app, type safe and customizable",
5
5
  "sideEffects": false,
6
6
  "repository": "https://github.com/remorses/unframer",
@@ -41,7 +41,6 @@
41
41
  "dependencies": {
42
42
  "async-sema": "^3.1.1",
43
43
  "cac": "^6.7.14",
44
- "dedent": "^1.5.3",
45
44
  "dprint-node": "^1.0.8",
46
45
  "esbuild": "^0.24.0",
47
46
  "esbuild-plugins-node-modules-polyfill": "^1.6.8",
@@ -49,12 +48,14 @@
49
48
  "find-up": "^5.0.0",
50
49
  "fs-extra": "^11.2.0",
51
50
  "json5": "^2.2.3",
51
+ "just-kebab-case": "^4.2.0",
52
52
  "marked": "^15.0.3",
53
53
  "marked-terminal": "^7.2.1",
54
54
  "nanospinner": "^1.2.0",
55
55
  "native-fetch": "^4.0.2",
56
56
  "picocolors": "^1.0.1",
57
- "real-framer-motion": "npm:framer-motion@11.2.10"
57
+ "real-framer-motion": "npm:framer-motion@11.2.10",
58
+ "string-dedent": "^3.0.1"
58
59
  },
59
60
  "devDependencies": {
60
61
  "@babel/core": "^7.24.9",
@@ -70,7 +71,7 @@
70
71
  "@types/fs-extra": "^11.0.4",
71
72
  "@types/node": "^22.7.4",
72
73
  "@types/react": "^18.3.12",
73
- "@xmorse/deployment-utils": "^0.2.18",
74
+ "@xmorse/deployment-utils": "^0.2.19",
74
75
  "concurrently": "^8.2.2",
75
76
  "openai": "^4.52.7",
76
77
  "posthtml": "^0.16.6",
@@ -0,0 +1,441 @@
1
+ import * as BabelTypes from '@babel/types'
2
+
3
+ import { PluginObj } from '@babel/core'
4
+ import { ImportDeclaration, ImportSpecifier, Identifier } from '@babel/types'
5
+ import BatchRenamer from './renamer'
6
+ import { logger } from './utils'
7
+
8
+ export function babelPluginDeduplicateImports({
9
+ types: t,
10
+ }: {
11
+ types: typeof BabelTypes
12
+ }): PluginObj {
13
+ const importAliasMap = new Map<
14
+ string,
15
+ Map<
16
+ string,
17
+ { consolidated: string; importName; path: ImportSpecifier; source }
18
+ >
19
+ >()
20
+
21
+ function addImport({
22
+ source,
23
+ local,
24
+ consolidated,
25
+ importName,
26
+ path,
27
+ }: {
28
+ source: string
29
+ local: string
30
+ consolidated: string
31
+ importName: string
32
+ path
33
+ }) {
34
+ if (!importAliasMap.has(source)) {
35
+ importAliasMap.set(source, new Map())
36
+ }
37
+ importAliasMap
38
+ .get(source)
39
+ ?.set(local, { consolidated, importName, path, source })
40
+ }
41
+
42
+ function getConsolidatedName({ source, importName, defaultOne }) {
43
+ const allSpecifiers = [...importAliasMap.values()].flatMap((x) => [
44
+ ...x.values(),
45
+ ])
46
+ const first = allSpecifiers.find((x) => {
47
+ if (importName === 'default' || importName === 'namespace') {
48
+ if (source !== x.source) {
49
+ return false
50
+ }
51
+ }
52
+ return x.importName === importName
53
+ })
54
+ return first?.consolidated || defaultOne
55
+ }
56
+
57
+ return {
58
+ visitor: {
59
+ ImportDeclaration(path) {
60
+ const source = path.node.source.value
61
+
62
+ path.node.specifiers.forEach((specifier) => {
63
+ if (
64
+ t.isImportSpecifier(specifier) &&
65
+ BabelTypes.isIdentifier(specifier.imported)
66
+ ) {
67
+ const importName = specifier.imported.name
68
+
69
+ const consolidatedName = getConsolidatedName({
70
+ source,
71
+ importName,
72
+ defaultOne: specifier.local.name,
73
+ })
74
+ addImport({
75
+ source,
76
+ local: specifier.local.name,
77
+ importName,
78
+ consolidated: consolidatedName,
79
+ path,
80
+ })
81
+ } else if (t.isImportDefaultSpecifier(specifier)) {
82
+ const importName = 'default'
83
+
84
+ const consolidatedName = getConsolidatedName({
85
+ source,
86
+ importName,
87
+ defaultOne: specifier.local.name,
88
+ })
89
+ addImport({
90
+ source,
91
+ local: specifier.local.name,
92
+ importName,
93
+ consolidated: consolidatedName,
94
+ path,
95
+ })
96
+ } else if (t.isImportNamespaceSpecifier(specifier)) {
97
+ const importName = 'namespace'
98
+
99
+ const consolidatedName = getConsolidatedName({
100
+ source,
101
+ importName,
102
+ defaultOne: specifier.local.name,
103
+ })
104
+ addImport({
105
+ source,
106
+ local: specifier.local.name,
107
+ importName,
108
+ consolidated: consolidatedName,
109
+ path,
110
+ })
111
+ }
112
+ })
113
+
114
+ // Remove the current import declaration to later add the consolidated one
115
+ // path.remove()
116
+ },
117
+ Program: {
118
+ exit(path) {
119
+ console.log(`renaming imports...`)
120
+ for (const [source, modMap] of importAliasMap) {
121
+ // rename import names to consolidated names
122
+ for (let [local, { consolidated, path: p }] of modMap) {
123
+ logger.log(
124
+ `renaming ${local} to ${consolidated}...`,
125
+ )
126
+ }
127
+ }
128
+
129
+ const map = new Map<string, string>(
130
+ [...importAliasMap.values()].flatMap((x) => {
131
+ return [...x.entries()]
132
+ .map(([prev, x]) => {
133
+ if (prev === x.consolidated) {
134
+ return
135
+ }
136
+ return [prev, x.consolidated]
137
+ })
138
+ .filter((x) => x !== undefined) as Array<
139
+ [string, string]
140
+ >
141
+ }),
142
+ )
143
+ // console.log([...map.entries()])
144
+ const renamer = new BatchRenamer(path.scope, map)
145
+ renamer.rename()
146
+
147
+ const importDecs = path.node.body.filter((node) =>
148
+ t.isImportDeclaration(node),
149
+ ) as ImportDeclaration[]
150
+
151
+ const definedImports = new Set<string>()
152
+ const later = [] as Function[]
153
+ console.log(`removing duplicates...`)
154
+ for (let importDec of importDecs) {
155
+ const source = importDec.source.value
156
+
157
+ const specifiers = importDec.specifiers
158
+ for (let specifier of specifiers) {
159
+ if (
160
+ !BabelTypes.isImportSpecifier(specifier) &&
161
+ !BabelTypes.isImportDefaultSpecifier(
162
+ specifier,
163
+ ) &&
164
+ !BabelTypes.isImportNamespaceSpecifier(
165
+ specifier,
166
+ )
167
+ ) {
168
+ continue
169
+ }
170
+ let importKey = ''
171
+ if (
172
+ BabelTypes.isImportDefaultSpecifier(specifier)
173
+ ) {
174
+ importKey = source + 'default'
175
+ } else if (
176
+ BabelTypes.isImportNamespaceSpecifier(specifier)
177
+ ) {
178
+ importKey = source + 'namespace'
179
+ } else {
180
+ if (
181
+ !BabelTypes.isIdentifier(specifier.imported)
182
+ ) {
183
+ continue
184
+ }
185
+ importKey = specifier.imported.name
186
+ }
187
+
188
+ if (definedImports.has(importKey)) {
189
+ later.push(() => {
190
+ console.log(
191
+ `removing ${importKey} from ${source}...`,
192
+ )
193
+
194
+ importDec.specifiers =
195
+ importDec.specifiers.filter(
196
+ (x) => x !== specifier,
197
+ )
198
+ if (!importDec.specifiers.length) {
199
+ const index = path.node.body.findIndex(
200
+ (x) => x === importDec,
201
+ )
202
+ path.node.body.splice(index, 1)
203
+ }
204
+ })
205
+ }
206
+ definedImports.add(importKey)
207
+ }
208
+ }
209
+ for (let fn of later) {
210
+ fn()
211
+ }
212
+ },
213
+ },
214
+ // Identifier(path) {
215
+ // const name = path.node.name
216
+ // const binding = path.scope.getBinding(name)
217
+
218
+ // if (binding && t.isImportSpecifier(binding.path.node)) {
219
+ // const source = (binding.path.parent as ImportDeclaration)
220
+ // .source.value
221
+ // const localName = getLocalImportName(source, name)
222
+
223
+ // if (localName && localName !== name) {
224
+ // path.node.name = localName
225
+ // }
226
+ // }
227
+ // },
228
+ },
229
+ }
230
+ }
231
+
232
+ export function babelPluginRenameExports({
233
+ map,
234
+ }: {
235
+ map: Map<string, string>
236
+ }) {
237
+ return {
238
+ name: 'rename-exports',
239
+ visitor: {
240
+ ExportNamedDeclaration(path) {
241
+ const { specifiers, declaration } = path.node
242
+ // Handle export specifiers like: export { something as oldName }
243
+ for (const specifier of specifiers) {
244
+ if (!BabelTypes.isExportSpecifier(specifier)) continue
245
+ const exported = specifier.exported
246
+ if (!BabelTypes.isIdentifier(exported)) continue
247
+ const oldName = exported.name
248
+ const newName = map.get(oldName)
249
+ if (newName) {
250
+ exported.name = newName
251
+ }
252
+ }
253
+ // Handle function declarations like: export function oldName1() {}
254
+ if (BabelTypes.isFunctionDeclaration(declaration)) {
255
+ const oldName = declaration.id?.name
256
+ if (oldName) {
257
+ const newName = map.get(oldName)
258
+ if (newName && declaration?.id) {
259
+ declaration.id.name = newName
260
+ }
261
+ }
262
+ }
263
+ },
264
+ ExportDefaultDeclaration(path) {
265
+ const { declaration } = path.node
266
+ if (BabelTypes.isIdentifier(declaration)) {
267
+ const oldName = declaration.name
268
+ const newName = map.get(oldName)
269
+ if (newName) {
270
+ declaration.name = newName
271
+ }
272
+ }
273
+ },
274
+ },
275
+ }
276
+ }
277
+
278
+ // Set of types that don't need expression containers
279
+ const noContainerTypes = new Set([
280
+ 'JSXElement',
281
+ // 'StringLiteral',
282
+ 'NumericLiteral',
283
+ ])
284
+
285
+ export function babelPluginJsxTransform() {
286
+ return {
287
+ name: 'jsx-transform',
288
+ visitor: {
289
+ CallExpression(path) {
290
+ // Check if it's a _jsx or _jsxs call
291
+ if (
292
+ !path.node.callee ||
293
+ !path.node.callee.name?.startsWith('_jsx')
294
+ ) {
295
+ return
296
+ }
297
+
298
+ // Remove /* @__PURE__ */ comments
299
+ if (path.node.leadingComments) {
300
+ path.node.leadingComments =
301
+ path.node.leadingComments.filter(
302
+ (comment) => !comment.value.includes('@__PURE__'),
303
+ )
304
+ }
305
+
306
+ const [elementArg, propsArg] = path.node.arguments
307
+
308
+ // Get the element type name
309
+ let elementName = ''
310
+ if (elementArg.type === 'MemberExpression') {
311
+ elementName = `${elementArg.object.name}.${elementArg.property.name}`
312
+ } else if (elementArg.type === 'StringLiteral') {
313
+ elementName = elementArg.value
314
+ } else if (elementArg.type === 'Identifier') {
315
+ elementName = elementArg.name
316
+ } else {
317
+ // Skip if we can't determine element name
318
+ return
319
+ }
320
+
321
+ // Convert to JSX element
322
+ const jsxElement: BabelTypes.JSXElement = {
323
+ type: 'JSXElement',
324
+ openingElement: {
325
+ type: 'JSXOpeningElement',
326
+ name: {
327
+ type: 'JSXIdentifier',
328
+ name: elementName,
329
+ },
330
+ attributes: [],
331
+ selfClosing: !propsArg.properties.find(
332
+ (p) => p.key?.name === 'children',
333
+ ),
334
+ },
335
+ closingElement: propsArg.properties.find(
336
+ (p) => p.key?.name === 'children',
337
+ )
338
+ ? {
339
+ type: 'JSXClosingElement',
340
+ name: {
341
+ type: 'JSXIdentifier',
342
+ name: elementName,
343
+ },
344
+ }
345
+ : null,
346
+ children: [],
347
+ }
348
+
349
+ // Add attributes
350
+ if (propsArg && propsArg.properties) {
351
+ propsArg.properties.forEach((prop) => {
352
+ if (prop.type === 'SpreadElement') {
353
+ jsxElement.openingElement.attributes.push({
354
+ type: 'JSXSpreadAttribute',
355
+ argument: prop.argument,
356
+ })
357
+ } else if (prop.key?.name === 'children') {
358
+ if (prop.value.type === 'ArrayExpression') {
359
+ jsxElement.children = prop.value.elements.map(
360
+ (element) => {
361
+ if (
362
+ noContainerTypes.has(
363
+ element.type,
364
+ ) ||
365
+ (element.type ===
366
+ 'CallExpression' &&
367
+ element.callee?.name?.startsWith(
368
+ '_jsx',
369
+ ))
370
+ ) {
371
+ return element
372
+ }
373
+ return {
374
+ type: 'JSXExpressionContainer',
375
+ expression: element,
376
+ }
377
+ },
378
+ )
379
+ } else {
380
+ if (
381
+ noContainerTypes.has(prop.value.type) ||
382
+ (prop.value.type === 'CallExpression' &&
383
+ prop.value.callee?.name?.startsWith(
384
+ '_jsx',
385
+ ))
386
+ ) {
387
+ jsxElement.children = [prop.value]
388
+ } else {
389
+ jsxElement.children = [
390
+ {
391
+ type: 'JSXExpressionContainer',
392
+ expression: prop.value,
393
+ },
394
+ ]
395
+ }
396
+ }
397
+ } else {
398
+ let attrName = prop.key?.name
399
+ if (
400
+ !attrName &&
401
+ prop.key?.type === 'StringLiteral'
402
+ ) {
403
+ attrName = prop.key.value
404
+ }
405
+ if (!attrName) {
406
+ console.log(
407
+ `no prop.key?.name for ${JSON.stringify(
408
+ prop,
409
+ )}`,
410
+ )
411
+ return
412
+ }
413
+
414
+ jsxElement.openingElement.attributes.push({
415
+ type: 'JSXAttribute',
416
+ name: {
417
+ type: 'JSXIdentifier',
418
+ name: attrName,
419
+ },
420
+ value: {
421
+ type: 'JSXExpressionContainer',
422
+ expression: prop.value,
423
+ },
424
+ })
425
+ }
426
+ })
427
+ }
428
+
429
+ path.replaceWith(jsxElement)
430
+ },
431
+ },
432
+ }
433
+ }
434
+
435
+ function jsonStringifyWithMaps(map) {
436
+ return JSON.stringify(
437
+ [...map],
438
+ (key, value) => (value instanceof Map ? [...value] : value),
439
+ 2,
440
+ )
441
+ }
package/src/cli.tsx CHANGED
@@ -9,19 +9,12 @@ import path, { basename } from 'path'
9
9
  import { BreakpointSizes } from './css.js'
10
10
  import { logger } from './utils.js'
11
11
  const configNames = ['unframer.config.json', 'unframer.json']
12
+ import kebabCase from 'just-kebab-case'
12
13
 
13
14
  export const cli = cac('unframer')
14
15
 
15
16
  let defaultOutDir = 'framer'
16
17
 
17
- function nameToFolder(name: string) {
18
- return name
19
- .replace(/[^a-zA-Z0-9]/g, '-') // Replace non-alphanumeric with dash
20
- .replace(/-+/g, '-') // Replace multiple dashes with single dash
21
- .replace(/^-|-$/g, '') // Remove leading/trailing dashes
22
- .toLowerCase()
23
- }
24
-
25
18
  cli.command('[projectId]', 'Run unframer with optional project ID')
26
19
  .option('--outDir <dir>', 'Output directory', { default: defaultOutDir })
27
20
  .action(async function main(projectId, options) {
@@ -46,10 +39,7 @@ cli.command('[projectId]', 'Run unframer with optional project ID')
46
39
  config: {
47
40
  outDir,
48
41
  components: Object.fromEntries(
49
- data.components.map((c) => [
50
- nameToFolder(c.name),
51
- c.url,
52
- ]),
42
+ data.components.map((c) => [kebabCase(c.name), c.url]),
53
43
  ),
54
44
  tokens: data.colorStyles,
55
45
  framerWebPages: data.framerWebPages || [],