synthesisui 0.4.0 → 0.4.1

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.
@@ -1,21 +1,44 @@
1
- import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
1
+ import { access, mkdir, readdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { basename, join } from "node:path";
3
3
  import { generateComponentFiles } from "../component-codegen.js";
4
4
  import { readProjectConfig, resolveRegistry } from "../config.js";
5
5
  import { body, section, snippet } from "../output.js";
6
6
  import { fetchComponent, postRefit, postSaveComponent, RegistryError, } from "../registry.js";
7
- /** Slugs materialized under `_synthesisui/ds/` in the project. */
7
+ /** Slugs INSTALLED under `_synthesisui/ds/` (a `.lock` marks a real install -
8
+ * a folder holding only refit artifacts doesn't count). */
8
9
  async function installedSlugs(root) {
9
10
  try {
10
11
  const entries = await readdir(join(root, "_synthesisui", "ds"), {
11
12
  withFileTypes: true,
12
13
  });
13
- return entries.filter((e) => e.isDirectory()).map((e) => e.name);
14
+ const slugs = [];
15
+ for (const entry of entries) {
16
+ if (!entry.isDirectory())
17
+ continue;
18
+ try {
19
+ await access(join(root, "_synthesisui", "ds", entry.name, ".lock"));
20
+ slugs.push(entry.name);
21
+ }
22
+ catch {
23
+ // artifacts-only folder (e.g. a refit before `add`) - not installed
24
+ }
25
+ }
26
+ return slugs;
14
27
  }
15
28
  catch {
16
29
  return [];
17
30
  }
18
31
  }
32
+ /** True when the system is actually installed (tokens.css present). */
33
+ async function isInstalled(root, slug) {
34
+ try {
35
+ await access(join(root, "_synthesisui", "ds", slug, ".lock"));
36
+ return true;
37
+ }
38
+ catch {
39
+ return false;
40
+ }
41
+ }
19
42
  /**
20
43
  * Marco B5 - the REVERSE bridge, from the CLI: takes a component that lives in
21
44
  * YOUR app (arbitrary React/CSS), re-expresses it in the design system's
@@ -116,6 +139,16 @@ export async function refit(file, opts) {
116
139
  materialized = true;
117
140
  console.log(`✓ ${config.componentsDir}/${res.name}/ → ${files.map((f) => f.filename).join(", ")} (styles: ${config.styles})`);
118
141
  }
142
+ // The materialized component references this system's tokens - without the
143
+ // install (tokens.css + scope) it renders unstyled. Say so, concretely.
144
+ if (!(await isInstalled(root, slug))) {
145
+ console.log(section("Heads up - system not installed here yet"));
146
+ console.log(body(`The component references "${slug}" tokens that this project doesn't have yet.`));
147
+ console.log("");
148
+ console.log(snippet([`npx synthesisui add ${slug}`]));
149
+ console.log("");
150
+ console.log(body("(then follow its one-time setup: global @import + data-ds scope)"));
151
+ }
119
152
  if (res.suggestedRule) {
120
153
  console.log(section("Suggested rule"));
121
154
  console.log(body("The AI inferred a reusable rule from this component:"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Traz design systems do SynthesisUI para qualquer projeto (materializa em _local/ds/).",
5
5
  "type": "module",
6
6
  "bin": {