Skip to content

Commit 9d21f28

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix(design): resolve namespace exports in central class inputs
1 parent 789f31a commit 9d21f28

2 files changed

Lines changed: 108 additions & 1 deletion

File tree

‎scripts/check-design-conformance-command.test.ts‎

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,3 +1086,107 @@ test('the relocated registry remains a central-system change and formatting stay
10861086
expect((await compare('{"version":1}', '{"version":2}')).findings[0].kind).toBe('system-change')
10871087
expect((await compare('{"version":1}', '{ "version": 1 }')).flagged).toBe(false)
10881088
})
1089+
1090+
test.each([
1091+
{
1092+
name: 'namespace export',
1093+
use: 'cn(styles.palette)',
1094+
before: "{'bg-red-500':true}",
1095+
after: "{'bg-blue-500':true}",
1096+
notify: true,
1097+
},
1098+
{
1099+
name: 'nested namespace export member',
1100+
use: 'cn(styles.palette.tone)',
1101+
before: "{tone:{'bg-red-500':true}}",
1102+
after: "{tone:{'bg-blue-500':true}}",
1103+
notify: true,
1104+
},
1105+
{
1106+
name: 'namespace barrel export alias',
1107+
use: 'cn(styles.colors)',
1108+
before: "{'bg-red-500':true}",
1109+
after: "{'bg-blue-500':true}",
1110+
barrel: true,
1111+
notify: true,
1112+
},
1113+
{
1114+
name: 'local namespace binding alias',
1115+
use: 'cn(forwarded.palette.tone)',
1116+
prefix: 'const forwarded=styles;',
1117+
before: "{tone:{'bg-red-500':true}}",
1118+
after: "{tone:{'bg-blue-500':true}}",
1119+
notify: true,
1120+
},
1121+
{
1122+
name: 'named import alias control',
1123+
use: 'cn(colors.tone)',
1124+
named: true,
1125+
before: "{tone:{'bg-red-500':true}}",
1126+
after: "{tone:{'bg-blue-500':true}}",
1127+
notify: true,
1128+
},
1129+
{
1130+
name: 'unused nested namespace member',
1131+
use: 'cn(styles.palette.tone)',
1132+
before: "{tone:{'bg-red-500':true},unused:{'bg-green-500':true}}",
1133+
after: "{tone:{'bg-red-500':true},unused:{'bg-blue-500':true}}",
1134+
notify: false,
1135+
},
1136+
{
1137+
name: 'shadowed namespace binding',
1138+
use: 'cn(styles.palette)',
1139+
prefix: "const styles={palette:{'rounded-md':true}};",
1140+
shadow: true,
1141+
before: "{'bg-red-500':true}",
1142+
after: "{'bg-blue-500':true}",
1143+
notify: false,
1144+
},
1145+
{
1146+
name: 'dynamic namespace export',
1147+
use: 'cn(styles[choice])',
1148+
prefix: 'declare const choice:string;',
1149+
before: "{'bg-red-500':true}",
1150+
after: "{'bg-blue-500':true}",
1151+
notify: false,
1152+
},
1153+
{
1154+
name: 'dynamic nested namespace member',
1155+
use: 'cn(styles.palette[choice])',
1156+
prefix: 'declare const choice:string;',
1157+
before: "{tone:{'bg-red-500':true}}",
1158+
after: "{tone:{'bg-blue-500':true}}",
1159+
notify: false,
1160+
},
1161+
])('namespace class inputs survive source-only edits through the real CLI: $name', (scenario) => {
1162+
const { repo } = fixture()
1163+
const sourceFile = 'packages/emcn/src/lib/palette.ts'
1164+
const write = (file: string, source: string) => {
1165+
mkdirSync(path.dirname(path.join(repo, file)), { recursive: true })
1166+
writeFileSync(path.join(repo, file), source)
1167+
}
1168+
write('packages/emcn/src/index.ts', "export {palette} from './lib/palette'")
1169+
write('packages/emcn/src/lib/barrel.ts', "export {palette as colors} from './palette'")
1170+
write(sourceFile, `export const palette=${scenario.before} as const`)
1171+
const imported = scenario.named
1172+
? "import {palette as colors} from '../lib/palette'"
1173+
: `import * as styles from '../lib/${scenario.barrel ? 'barrel' : 'palette'}'`
1174+
write(
1175+
'packages/emcn/src/components/consumer.tsx',
1176+
`${imported};declare function cn(...args:unknown[]):string;${scenario.shadow ? `function Consumer(){${scenario.prefix}return <div className={${scenario.use}}/>}` : `${scenario.prefix ?? ''}const Consumer=()=> <div className={${scenario.use}}/>`}`
1177+
)
1178+
write(ui, 'const A=()=> <div/>')
1179+
const base = commit(repo)
1180+
write(sourceFile, `export const palette=${scenario.after} as const`)
1181+
const child = run(['--repo', repo, '--base', base, '--working-tree', '--format', 'json'])
1182+
expect([0, 1], child.stderr).toContain(child.status)
1183+
const report = JSON.parse(child.stdout) as Report
1184+
expect(report.status, child.stdout).toBe('completed')
1185+
expect(git(repo, ['diff', '--name-only', base]).toString().trim()).toBe(sourceFile)
1186+
expect(
1187+
report.findings.filter(
1188+
(finding) => finding.file === sourceFile && finding.property === 'background-color'
1189+
),
1190+
child.stdout
1191+
).toHaveLength(scenario.notify ? 1 : 0)
1192+
})

‎scripts/design-conformance/source-summary.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,10 @@ export function summarize(ast: t.File, file: string): SourceSummary {
183183
: ''
184184
: key(p.node.property)
185185
const object = classRef(p.get('object'), next)
186-
return object && member ? { ref: object.ref, path: [...object.path, member] } : undefined
186+
if (!object || !member) return undefined
187+
return object.ref.endsWith('#*')
188+
? { ref: object.ref.slice(0, -1) + member, path: object.path }
189+
: { ref: object.ref, path: [...object.path, member] }
187190
}
188191
if (!p.isIdentifier()) return undefined
189192
const binding = p.scope.getBinding(p.node.name)

0 commit comments

Comments
 (0)