synthesisui 0.16.293 → 0.16.294

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.
@@ -34,6 +34,22 @@ async function writeCn(root, compDir, slug) {
34
34
  /** Slugs/names are kebab-case by contract; reject anything else before it ever
35
35
  * reaches a filesystem path (defense-in-depth against `../` traversal). */
36
36
  const SAFE_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
37
+ /**
38
+ * O NOME QUE O ARQUIVO VAI TER - o do blueprint, ou o que ele pediu.
39
+ *
40
+ * Puro e exportado porque é a decisão, e ela precisa ser provada sem rede nem disco. O nome vem da
41
+ * linha de comando e termina dentro de um `join`, então a validação é defesa em profundidade e não
42
+ * capricho: `--as ../escape` não pode chegar ao sistema de arquivos.
43
+ */
44
+ export function localName(blueprint, asked) {
45
+ const wanted = asked?.trim();
46
+ if (!wanted)
47
+ return blueprint;
48
+ if (!SAFE_NAME.test(wanted)) {
49
+ throw new RegistryError(`Invalid --as "${wanted}" - use kebab-case, like \`--as my-${blueprint}\`.`);
50
+ }
51
+ return wanted;
52
+ }
37
53
  /**
38
54
  * Brings ONE component from a design system into the project (granular "bring
39
55
  * specific", INS-18 fatia 3):
@@ -172,7 +188,15 @@ export async function component(slug, name, opts) {
172
188
  console.log(body("Nothing of yours was touched. Which name it takes is your call, not ours."));
173
189
  return;
174
190
  }
175
- const compDir = join(root, config.componentsDir, res.name);
191
+ /**
192
+ * O NOME QUE O ARQUIVO VAI TER - ver `localName`.
193
+ *
194
+ * `--as` é o que permite ele VER o que um blueprint produz num repositório que já tem o
195
+ * componente. O CSS não muda de nome: a receita é a do blueprint, e as classes dela são
196
+ * `.ds-<blueprint>` - o componente novo veste o mesmo desenho, com o nome dele no arquivo.
197
+ */
198
+ const local = localName(res.name, opts.as);
199
+ const compDir = join(root, config.componentsDir, local);
176
200
  await mkdir(compDir, { recursive: true });
177
201
  let filenames;
178
202
  if (wantInteractive) {
@@ -180,10 +204,10 @@ export async function component(slug, name, opts) {
180
204
  // it wears (.css) + the barrel. Ignores the css|tailwind flavor - the
181
205
  // template drives itself off the .ds-* classes.
182
206
  const tsx = interactiveTemplate(res.name);
183
- await writeFile(join(compDir, `${res.name}.tsx`), tsx, "utf8");
184
- await writeFile(join(compDir, `${res.name}.css`), `${css}\n`, "utf8");
185
- await writeFile(join(compDir, "index.ts"), `export * from "./${res.name}";\n`, "utf8");
186
- filenames = [`${res.name}.tsx`, `${res.name}.css`, "index.ts"];
207
+ await writeFile(join(compDir, `${local}.tsx`), tsx, "utf8");
208
+ await writeFile(join(compDir, `${local}.css`), `${css}\n`, "utf8");
209
+ await writeFile(join(compDir, "index.ts"), `export * from "./${local}";\n`, "utf8");
210
+ filenames = [`${local}.tsx`, `${local}.css`, "index.ts"];
187
211
  }
188
212
  else {
189
213
  const files = generateComponentFiles(slug, res.name, res.recipe, css, res.version, config.styles, await reactMajorOf(root),
@@ -195,7 +219,17 @@ export async function component(slug, name, opts) {
195
219
  * it, so the TSX and the stylesheet in the same folder agree by
196
220
  * construction. Falling back to disk keeps an older registry working.
197
221
  */
198
- res.classNames ?? (await readInstalledConvention(root, slug)), res.name, await readInstalledScheme(root, slug));
222
+ res.classNames ?? (await readInstalledConvention(root, slug)),
223
+ /**
224
+ * O NOME LOCAL, e o codegen já sabia fazer isto - ver `localName` em
225
+ * `component-codegen.ts`: *"A project that already exports `Button` should not have to give
226
+ * the name up to install ours"*. A capacidade existia e nenhuma flag a alcançava, então a
227
+ * recusa oferecia `--as` e o comando ignorava.
228
+ *
229
+ * O ARQUIVO e o EXPORT levam o nome dele; a CLASSE continua sendo a do blueprint. Um
230
+ * `<CardPreview>` vestindo `.ds-card` está estilizado certo e não faz sombra em nada dele.
231
+ */
232
+ local, await readInstalledScheme(root, slug));
199
233
  /**
200
234
  * AS DECLARAÇÕES DO ARQUIVO DELE QUE O INTERPRETADOR NÃO LEU - ver `unread-for-component.ts`.
201
235
  *
@@ -217,7 +251,7 @@ export async function component(slug, name, opts) {
217
251
  filenames = files.map((f) => f.filename);
218
252
  }
219
253
  const flavor = wantInteractive ? "interactive" : `styles: ${config.styles}`;
220
- console.log(`✓ ${config.componentsDir}/${res.name}/ → ${filenames.join(", ")} (${flavor})`);
254
+ console.log(`✓ ${config.componentsDir}/${local}/ → ${filenames.join(", ")} (${flavor})${local === res.name ? "" : ` - the "${res.name}" blueprint, under your name`}`);
221
255
  }
222
256
  else if (opts.interactive && !hasInteractiveTemplate(res.name)) {
223
257
  console.log(` note: no interactive template for "${res.name}" - materialized the standard shell.`);
package/dist/index.js CHANGED
@@ -522,6 +522,14 @@ async function main() {
522
522
  version,
523
523
  artifactsOnly: flags["artifacts-only"] === true,
524
524
  interactive: flags.interactive === true,
525
+ /**
526
+ * O NOME LOCAL - ver `localName` em `component.ts`.
527
+ *
528
+ * A recusa por nome ocupado já oferecia `--as`, e a flag não era lida: quem seguia a
529
+ * instrução da tela recebia o arquivo com o nome de sempre.
530
+ */
531
+ ...(typeof flags.as === "string" ? { as: flags.as } : {}),
532
+ ...(flags.force === true ? { force: true } : {}),
525
533
  });
526
534
  break;
527
535
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.293",
3
+ "version": "0.16.294",
4
4
  "description": "Bring SynthesisUI design systems into any project - tokens, typed components, whole pages and an agent-ready CLAUDE.md manifest.",
5
5
  "type": "module",
6
6
  "bin": {