@astryxdesign/cli 0.1.6-canary.c899736 → 0.1.6-canary.d3e7822
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/cli",
|
|
3
|
-
"version": "0.1.6-canary.
|
|
3
|
+
"version": "0.1.6-canary.d3e7822",
|
|
4
4
|
"displayName": "CLI",
|
|
5
5
|
"description": "Scaffold projects, browse templates, generate themes, and get agent-ready docs from the command line.",
|
|
6
6
|
"author": "Meta Open Source",
|
|
@@ -79,10 +79,10 @@
|
|
|
79
79
|
"zod": "^4.4.3"
|
|
80
80
|
},
|
|
81
81
|
"peerDependencies": {
|
|
82
|
-
"@astryxdesign/charts": "0.1.6-canary.
|
|
83
|
-
"@astryxdesign/core": "0.1.6-canary.
|
|
84
|
-
"@astryxdesign/lab": "0.1.6-canary.
|
|
85
|
-
"@astryxdesign/theme-neutral": "0.1.6-canary.
|
|
82
|
+
"@astryxdesign/charts": "0.1.6-canary.d3e7822",
|
|
83
|
+
"@astryxdesign/core": "0.1.6-canary.d3e7822",
|
|
84
|
+
"@astryxdesign/lab": "0.1.6-canary.d3e7822",
|
|
85
|
+
"@astryxdesign/theme-neutral": "0.1.6-canary.d3e7822",
|
|
86
86
|
"gpt-tokenizer": "^3.4.0"
|
|
87
87
|
},
|
|
88
88
|
"peerDependenciesMeta": {
|
|
@@ -100,10 +100,10 @@
|
|
|
100
100
|
}
|
|
101
101
|
},
|
|
102
102
|
"devDependencies": {
|
|
103
|
-
"@astryxdesign/charts": "0.1.6-canary.
|
|
104
|
-
"@astryxdesign/core": "0.1.6-canary.
|
|
105
|
-
"@astryxdesign/lab": "0.1.6-canary.
|
|
106
|
-
"@astryxdesign/theme-neutral": "0.1.6-canary.
|
|
103
|
+
"@astryxdesign/charts": "0.1.6-canary.d3e7822",
|
|
104
|
+
"@astryxdesign/core": "0.1.6-canary.d3e7822",
|
|
105
|
+
"@astryxdesign/lab": "0.1.6-canary.d3e7822",
|
|
106
|
+
"@astryxdesign/theme-neutral": "0.1.6-canary.d3e7822",
|
|
107
107
|
"gpt-tokenizer": "^3.4.0"
|
|
108
108
|
},
|
|
109
109
|
"scripts": {
|
package/src/codemods/transforms/v0.1.7/__tests__/rename-table-renderprops-styles-to-xstyle.test.mjs
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
import {describe, it, expect} from 'vitest';
|
|
4
|
+
|
|
5
|
+
async function applyTransform(source) {
|
|
6
|
+
const {default: transform} = await import(
|
|
7
|
+
'../rename-table-renderprops-styles-to-xstyle.mjs'
|
|
8
|
+
);
|
|
9
|
+
const jscodeshift = (await import('jscodeshift')).default;
|
|
10
|
+
const j = jscodeshift.withParser('tsx');
|
|
11
|
+
const api = {jscodeshift: j, stats: () => {}, report: () => {}};
|
|
12
|
+
const file = {source, path: 'test.tsx'};
|
|
13
|
+
const result = transform(file, api);
|
|
14
|
+
return result ?? source;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe('rename-table-renderprops-styles-to-xstyle', () => {
|
|
18
|
+
it('renames `props.styles` reads when the param is typed TableRenderProps', async () => {
|
|
19
|
+
const input = `function transformTable(props: TableRenderProps) {
|
|
20
|
+
return {...props, styles: [...props.styles, tableStyles.base]};
|
|
21
|
+
}`;
|
|
22
|
+
const output = await applyTransform(input);
|
|
23
|
+
expect(output).toContain('...props.xstyle');
|
|
24
|
+
expect(output).toContain('xstyle: [');
|
|
25
|
+
expect(output).not.toMatch(/\bstyles:/);
|
|
26
|
+
expect(output).not.toContain('props.styles');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('renames reads/writes for BodyCellRenderProps', async () => {
|
|
30
|
+
const input = `const transformBodyCell = (props: BodyCellRenderProps) => ({
|
|
31
|
+
...props,
|
|
32
|
+
styles: [...props.styles, cellStyles.padded],
|
|
33
|
+
});`;
|
|
34
|
+
const output = await applyTransform(input);
|
|
35
|
+
expect(output).toContain('...props.xstyle');
|
|
36
|
+
expect(output).toContain('xstyle: [');
|
|
37
|
+
expect(output).not.toContain('props.styles');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('handles all six render-prop interface names as param types', async () => {
|
|
41
|
+
for (const typeName of [
|
|
42
|
+
'TableRenderProps',
|
|
43
|
+
'HeaderRowRenderProps',
|
|
44
|
+
'HeaderCellRenderProps',
|
|
45
|
+
'BodyRowRenderProps',
|
|
46
|
+
'BodyCellRenderProps',
|
|
47
|
+
'ScrollWrapperRenderProps',
|
|
48
|
+
]) {
|
|
49
|
+
const input = `function t(p: ${typeName}) { return p.styles; }`;
|
|
50
|
+
const output = await applyTransform(input);
|
|
51
|
+
expect(output).toContain('p.xstyle');
|
|
52
|
+
expect(output).not.toContain('p.styles');
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('renames the `styles:` key on a render-prop-shaped object literal (htmlProps + styles siblings)', async () => {
|
|
57
|
+
const input = `const rp = {htmlProps: {}, styles: []};`;
|
|
58
|
+
const output = await applyTransform(input);
|
|
59
|
+
expect(output).toContain('xstyle: []');
|
|
60
|
+
expect(output).not.toMatch(/\bstyles:/);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('does NOT touch an unrelated `styles` from stylex.create', async () => {
|
|
64
|
+
const input = `import * as stylex from '@stylexjs/stylex';
|
|
65
|
+
const styles = stylex.create({base: {color: 'red'}});
|
|
66
|
+
function useStuff() {
|
|
67
|
+
return stylex.props(styles.base);
|
|
68
|
+
}`;
|
|
69
|
+
const output = await applyTransform(input);
|
|
70
|
+
// No render-prop binding, no htmlProps-shaped object -> unchanged
|
|
71
|
+
expect(output).toContain('const styles = stylex.create');
|
|
72
|
+
expect(output).toContain('styles.base');
|
|
73
|
+
expect(output).not.toContain('xstyle');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('does NOT rename `.styles` on an unrelated (untyped) object even when a render-prop binding exists elsewhere', async () => {
|
|
77
|
+
const input = `function transformTable(props: TableRenderProps) {
|
|
78
|
+
const theme = getTheme();
|
|
79
|
+
return {...props, styles: [...props.styles, theme.styles.base]};
|
|
80
|
+
}`;
|
|
81
|
+
const output = await applyTransform(input);
|
|
82
|
+
// props.styles renamed; theme.styles left alone
|
|
83
|
+
expect(output).toContain('...props.xstyle');
|
|
84
|
+
expect(output).toContain('theme.styles.base');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('returns undefined for files with no render-prop usage', async () => {
|
|
88
|
+
const {default: transform} = await import(
|
|
89
|
+
'../rename-table-renderprops-styles-to-xstyle.mjs'
|
|
90
|
+
);
|
|
91
|
+
const jscodeshift = (await import('jscodeshift')).default;
|
|
92
|
+
const j = jscodeshift.withParser('tsx');
|
|
93
|
+
const api = {jscodeshift: j, stats: () => {}, report: () => {}};
|
|
94
|
+
const source = `const styles = {a: 1};\nconst x = styles.a;`;
|
|
95
|
+
const result = transform({source, path: 'test.tsx'}, api);
|
|
96
|
+
expect(result).toBeUndefined();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('returns undefined for already-migrated code (xstyle only)', async () => {
|
|
100
|
+
const {default: transform} = await import(
|
|
101
|
+
'../rename-table-renderprops-styles-to-xstyle.mjs'
|
|
102
|
+
);
|
|
103
|
+
const jscodeshift = (await import('jscodeshift')).default;
|
|
104
|
+
const j = jscodeshift.withParser('tsx');
|
|
105
|
+
const api = {jscodeshift: j, stats: () => {}, report: () => {}};
|
|
106
|
+
const source = `function transformTable(props: TableRenderProps) {
|
|
107
|
+
return {...props, xstyle: [...props.xstyle]};
|
|
108
|
+
}`;
|
|
109
|
+
const result = transform({source, path: 'test.tsx'}, api);
|
|
110
|
+
expect(result).toBeUndefined();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
import migrateTableTablePropsToDirectProps, {
|
|
10
10
|
meta as migrateTableTablePropsToDirectPropsMeta,
|
|
11
11
|
} from './migrate-table-tableprops-to-direct-props.mjs';
|
|
12
|
+
import renameTableRenderPropsStylesToXstyle, {
|
|
13
|
+
meta as renameTableRenderPropsStylesToXstyleMeta,
|
|
14
|
+
} from './rename-table-renderprops-styles-to-xstyle.mjs';
|
|
12
15
|
|
|
13
16
|
export default [
|
|
14
17
|
{
|
|
@@ -16,4 +19,9 @@ export default [
|
|
|
16
19
|
transform: migrateTableTablePropsToDirectProps,
|
|
17
20
|
meta: migrateTableTablePropsToDirectPropsMeta,
|
|
18
21
|
},
|
|
22
|
+
{
|
|
23
|
+
name: 'rename-table-renderprops-styles-to-xstyle',
|
|
24
|
+
transform: renameTableRenderPropsStylesToXstyle,
|
|
25
|
+
meta: renameTableRenderPropsStylesToXstyleMeta,
|
|
26
|
+
},
|
|
19
27
|
];
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Codemod: Rename Table render-prop `styles` field to `xstyle`
|
|
5
|
+
*
|
|
6
|
+
* As of v0.1.7, the Table plugin render-prop interfaces
|
|
7
|
+
* (`TableRenderProps`, `HeaderRowRenderProps`, `HeaderCellRenderProps`,
|
|
8
|
+
* `BodyRowRenderProps`, `BodyCellRenderProps`, `ScrollWrapperRenderProps`)
|
|
9
|
+
* and the `scrollWrapper` component contract renamed their StyleX array
|
|
10
|
+
* field `styles` -> `xstyle`, matching the prop name sub-components
|
|
11
|
+
* receive it under.
|
|
12
|
+
*
|
|
13
|
+
* Custom plugin authors read `props.styles` and write `styles: [...]`
|
|
14
|
+
* inside their transform functions (`transformTable`, `transformHeaderRow`,
|
|
15
|
+
* `transformHeaderCell`, `transformBodyRow`, `transformBodyCell`,
|
|
16
|
+
* `transformScrollWrapper`). This codemod renames those reads and writes.
|
|
17
|
+
*
|
|
18
|
+
* A blind global `styles` rename is unsafe — `styles` is also the
|
|
19
|
+
* conventional local name for a `stylex.create({...})` bag, which is
|
|
20
|
+
* unrelated. So this transform only rewrites `styles` when it is
|
|
21
|
+
* *scoped to a render-prop object*: a function parameter (or a variable)
|
|
22
|
+
* whose TypeScript type annotation is one of the render-prop interfaces.
|
|
23
|
+
* Within such a scope it rewrites:
|
|
24
|
+
*
|
|
25
|
+
* - `<param>.styles` -> `<param>.xstyle` (member reads/writes)
|
|
26
|
+
* - `{ ..., styles: [...] }` -> `{ ..., xstyle: [...] }`
|
|
27
|
+
* for object literals that carry the render-prop shape (a sibling
|
|
28
|
+
* `htmlProps` key), and object literals assigned/spread from the
|
|
29
|
+
* tracked render-prop binding.
|
|
30
|
+
*
|
|
31
|
+
* Ambiguous cases that can't be resolved from types alone (e.g. a
|
|
32
|
+
* render-prop object passed through an untyped variable, or a `styles`
|
|
33
|
+
* bag from `stylex.create`) are left untouched, so the transform never
|
|
34
|
+
* renames an unrelated `styles`. This mirrors the conservative,
|
|
35
|
+
* scope-limited approach of the sibling
|
|
36
|
+
* `migrate-table-tableprops-to-direct-props` codemod.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
export const meta = {
|
|
40
|
+
title: 'Rename Table render-prop `styles` field to `xstyle`',
|
|
41
|
+
description:
|
|
42
|
+
'Renames the `styles` StyleX-array field to `xstyle` on Table plugin ' +
|
|
43
|
+
'render-prop objects (TableRenderProps, HeaderRowRenderProps, ' +
|
|
44
|
+
'HeaderCellRenderProps, BodyRowRenderProps, BodyCellRenderProps, ' +
|
|
45
|
+
'ScrollWrapperRenderProps) inside plugin transform functions. Reads ' +
|
|
46
|
+
'(`props.styles`) and writes (`styles: [...]`) are renamed; unrelated ' +
|
|
47
|
+
'`styles` bindings (e.g. from stylex.create) are left untouched.',
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/** The render-prop interface type names whose `styles` field became `xstyle`. */
|
|
51
|
+
const RENDER_PROP_TYPES = new Set([
|
|
52
|
+
'TableRenderProps',
|
|
53
|
+
'HeaderRowRenderProps',
|
|
54
|
+
'HeaderCellRenderProps',
|
|
55
|
+
'BodyRowRenderProps',
|
|
56
|
+
'BodyCellRenderProps',
|
|
57
|
+
'ScrollWrapperRenderProps',
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
/** Resolve the base type name from a TS type annotation node. */
|
|
61
|
+
function typeNameOf(typeAnnotation) {
|
|
62
|
+
// `x: TableRenderProps`
|
|
63
|
+
const t = typeAnnotation?.typeAnnotation ?? typeAnnotation;
|
|
64
|
+
if (!t) return null;
|
|
65
|
+
if (t.type === 'TSTypeReference' && t.typeName?.type === 'Identifier') {
|
|
66
|
+
return t.typeName.name;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export default function transformer(file, api) {
|
|
72
|
+
const j = api.jscodeshift;
|
|
73
|
+
const root = j(file.source);
|
|
74
|
+
let hasChanges = false;
|
|
75
|
+
|
|
76
|
+
// --- 1. Collect binding names typed as a render-prop interface. ---
|
|
77
|
+
// Function/arrow params: (props: TableRenderProps) => ...
|
|
78
|
+
const renderPropBindings = new Set();
|
|
79
|
+
|
|
80
|
+
function collectParam(param) {
|
|
81
|
+
if (
|
|
82
|
+
param.type === 'Identifier' &&
|
|
83
|
+
RENDER_PROP_TYPES.has(typeNameOf(param.typeAnnotation))
|
|
84
|
+
) {
|
|
85
|
+
renderPropBindings.add(param.name);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
root
|
|
90
|
+
.find(j.Function)
|
|
91
|
+
.forEach((p) => (p.node.params ?? []).forEach(collectParam));
|
|
92
|
+
root
|
|
93
|
+
.find(j.FunctionDeclaration)
|
|
94
|
+
.forEach((p) => (p.node.params ?? []).forEach(collectParam));
|
|
95
|
+
root
|
|
96
|
+
.find(j.FunctionExpression)
|
|
97
|
+
.forEach((p) => (p.node.params ?? []).forEach(collectParam));
|
|
98
|
+
root
|
|
99
|
+
.find(j.ArrowFunctionExpression)
|
|
100
|
+
.forEach((p) => (p.node.params ?? []).forEach(collectParam));
|
|
101
|
+
|
|
102
|
+
// Variable declarations: `const rp: BodyCellRenderProps = ...`
|
|
103
|
+
root.find(j.VariableDeclarator).forEach((p) => {
|
|
104
|
+
const id = p.node.id;
|
|
105
|
+
if (
|
|
106
|
+
id?.type === 'Identifier' &&
|
|
107
|
+
RENDER_PROP_TYPES.has(typeNameOf(id.typeAnnotation))
|
|
108
|
+
) {
|
|
109
|
+
renderPropBindings.add(id.name);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const hasTypedBinding = renderPropBindings.size > 0;
|
|
114
|
+
|
|
115
|
+
// Also detect object literals that are structurally a render-prop object.
|
|
116
|
+
// Two shapes qualify:
|
|
117
|
+
// 1. An `htmlProps` sibling key alongside a `styles`/`xstyle` key — the
|
|
118
|
+
// literal shape a transform function returns from scratch.
|
|
119
|
+
// 2. A spread of a tracked render-prop binding (`{...props, styles: [...]}`)
|
|
120
|
+
// — the common "carry the render-prop object forward, override styles"
|
|
121
|
+
// shape. (Only counts when `renderPropBindings` is non-empty.)
|
|
122
|
+
function isRenderPropShapedObject(objExpr) {
|
|
123
|
+
if (objExpr.type !== 'ObjectExpression') return false;
|
|
124
|
+
const keyNames = objExpr.properties
|
|
125
|
+
.map((pr) =>
|
|
126
|
+
pr.type === 'ObjectProperty' || pr.type === 'Property'
|
|
127
|
+
? pr.key?.name ?? pr.key?.value
|
|
128
|
+
: null,
|
|
129
|
+
)
|
|
130
|
+
.filter(Boolean);
|
|
131
|
+
if (keyNames.includes('htmlProps') && keyNames.includes('styles')) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
// Spread of a tracked render-prop binding.
|
|
135
|
+
const spreadsRenderProp = objExpr.properties.some(
|
|
136
|
+
(pr) =>
|
|
137
|
+
(pr.type === 'SpreadElement' || pr.type === 'ExperimentalSpreadProperty') &&
|
|
138
|
+
pr.argument?.type === 'Identifier' &&
|
|
139
|
+
renderPropBindings.has(pr.argument.name),
|
|
140
|
+
);
|
|
141
|
+
return spreadsRenderProp && keyNames.includes('styles');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!hasTypedBinding) {
|
|
145
|
+
// Nothing is typed as a render-prop interface. Only rewrite clearly
|
|
146
|
+
// render-prop-shaped object literals (htmlProps + styles siblings);
|
|
147
|
+
// never touch bare `styles` in this file (too ambiguous).
|
|
148
|
+
let touched = false;
|
|
149
|
+
root.find(j.ObjectExpression).forEach((p) => {
|
|
150
|
+
if (!isRenderPropShapedObject(p.node)) return;
|
|
151
|
+
for (const prop of p.node.properties) {
|
|
152
|
+
if (
|
|
153
|
+
(prop.type === 'ObjectProperty' || prop.type === 'Property') &&
|
|
154
|
+
!prop.computed &&
|
|
155
|
+
prop.key?.type === 'Identifier' &&
|
|
156
|
+
prop.key.name === 'styles'
|
|
157
|
+
) {
|
|
158
|
+
prop.key.name = 'xstyle';
|
|
159
|
+
touched = true;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
if (!touched) return undefined;
|
|
164
|
+
return root.toSource({quote: 'single'});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// --- 2. Rewrite `<binding>.styles` member access -> `.xstyle`. ---
|
|
168
|
+
root.find(j.MemberExpression).forEach((p) => {
|
|
169
|
+
const {object, property, computed} = p.node;
|
|
170
|
+
if (computed) return;
|
|
171
|
+
if (property?.type !== 'Identifier' || property.name !== 'styles') return;
|
|
172
|
+
if (object?.type !== 'Identifier' || !renderPropBindings.has(object.name)) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
property.name = 'xstyle';
|
|
176
|
+
hasChanges = true;
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// --- 3. Rewrite `styles:` keys on render-prop-shaped object literals. ---
|
|
180
|
+
root.find(j.ObjectExpression).forEach((p) => {
|
|
181
|
+
if (!isRenderPropShapedObject(p.node)) return;
|
|
182
|
+
for (const prop of p.node.properties) {
|
|
183
|
+
if (
|
|
184
|
+
(prop.type === 'ObjectProperty' || prop.type === 'Property') &&
|
|
185
|
+
!prop.computed &&
|
|
186
|
+
prop.key?.type === 'Identifier' &&
|
|
187
|
+
prop.key.name === 'styles'
|
|
188
|
+
) {
|
|
189
|
+
prop.key.name = 'xstyle';
|
|
190
|
+
hasChanges = true;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
if (!hasChanges) return undefined;
|
|
196
|
+
return root.toSource({quote: 'single'});
|
|
197
|
+
}
|