synthesisui 0.16.261 → 0.16.263
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/dist/commands/import.js +38 -3
- package/dist/doctor/architecture.js +65 -3
- package/dist/index.js +13 -1
- package/dist/naming-queue.js +56 -0
- package/package.json +1 -1
package/dist/commands/import.js
CHANGED
|
@@ -4,7 +4,7 @@ import { anatomyFromSketch } from "../anatomy-from-sketch.js";
|
|
|
4
4
|
import { resolveAnatomy, resolveFlatParts, safePartName, } from "../anatomy-read.js";
|
|
5
5
|
import { readCredentials, readToken, resolveRegistry, sameRegistry, } from "../config.js";
|
|
6
6
|
import { declaredElsewhere } from "../declared-elsewhere.js";
|
|
7
|
-
import { architectureRule, describeArchitecture, describeChoice, detectArchitectures, } from "../doctor/architecture.js";
|
|
7
|
+
import { architectureRule, componentHome, describeArchitecture, describeChoice, detectArchitectures, homeLine, proposeNewHome, } from "../doctor/architecture.js";
|
|
8
8
|
import { findBrokenRefs } from "../doctor/broken-refs.js";
|
|
9
9
|
import { nestingRules, propRules, readDefinitionProps, readNesting, readRuntime, } from "../doctor/call-sites.js";
|
|
10
10
|
import { asCatalogueTable, describeFallback, fetchCatalogue, } from "../doctor/catalogue-fetch.js";
|
|
@@ -37,6 +37,7 @@ import { frontierKind, packageRoot } from "../frontier-kind.js";
|
|
|
37
37
|
import { withLibraryStructure } from "../library-structure.js";
|
|
38
38
|
import { mergeCensus } from "../merge-census.js";
|
|
39
39
|
import { claimName } from "../name-claim.js";
|
|
40
|
+
import { namingQueue } from "../naming-queue.js";
|
|
40
41
|
import { body, paint, section } from "../output.js";
|
|
41
42
|
import { phase, startProgress } from "../progress.js";
|
|
42
43
|
import { detectStack, resolveDeps, stackVersions } from "../stack.js";
|
|
@@ -1928,6 +1929,18 @@ export async function takeCensus(root, opts) {
|
|
|
1928
1929
|
const brokenRefs = findBrokenRefs(sources, declaredNames);
|
|
1929
1930
|
const conventions = detectConventions(sources);
|
|
1930
1931
|
const classStyle = detectClassStyle(sources);
|
|
1932
|
+
/**
|
|
1933
|
+
* A FILA DE NOMES, computada com os MESMOS insumos que o envio usa - ver `namingQueue`.
|
|
1934
|
+
*
|
|
1935
|
+
* O crosswalk e o manifesto entram porque é o que distingue um componente DELES de uma peça de
|
|
1936
|
+
* terceiro, e os dois casos são nós já nomeados. Sem eles a fila cobraria trabalho que não
|
|
1937
|
+
* existe, que é exatamente o defeito que ela vem medir.
|
|
1938
|
+
*/
|
|
1939
|
+
const naming = namingQueue(looks, (name) => {
|
|
1940
|
+
const c = components.find((x) => x.name === name && !x.from);
|
|
1941
|
+
const target = c?.canonical ?? (c?.bucket === "exclusive" ? c.name : null);
|
|
1942
|
+
return target ? safePartName(target) : null;
|
|
1943
|
+
}, (pkg) => versions[pkg]);
|
|
1931
1944
|
return {
|
|
1932
1945
|
census: 1,
|
|
1933
1946
|
project: {
|
|
@@ -1964,6 +1977,7 @@ export async function takeCensus(root, opts) {
|
|
|
1964
1977
|
...(conventions.length > 0 ? { conventions } : {}),
|
|
1965
1978
|
classStyle,
|
|
1966
1979
|
...(Object.keys(looks).length > 0 ? { looks } : {}),
|
|
1980
|
+
...(naming.components > 0 ? { naming } : {}),
|
|
1967
1981
|
...(schemes.alt.size > 0
|
|
1968
1982
|
? { declaredAlt: Object.fromEntries(schemes.alt) }
|
|
1969
1983
|
: {}),
|
|
@@ -2026,8 +2040,16 @@ export async function takeCensus(root, opts) {
|
|
|
2026
2040
|
? {
|
|
2027
2041
|
architectures: architectures.slice(0, 6).map((a) => ({
|
|
2028
2042
|
...a,
|
|
2029
|
-
|
|
2043
|
+
/** O caminho e a frase que a PERGUNTA usa verbatim - ver `componentHome`. */
|
|
2044
|
+
home: componentHome(a, scopeLabel),
|
|
2045
|
+
line: homeLine(a),
|
|
2046
|
+
rule: architectureRule(a, scopeLabel),
|
|
2030
2047
|
})),
|
|
2048
|
+
...(proposeNewHome(architectures, scopeLabel)
|
|
2049
|
+
? {
|
|
2050
|
+
newComponentHome: proposeNewHome(architectures, scopeLabel),
|
|
2051
|
+
}
|
|
2052
|
+
: {}),
|
|
2031
2053
|
}
|
|
2032
2054
|
: {}),
|
|
2033
2055
|
...(skips.length > 0
|
|
@@ -3570,7 +3592,11 @@ export async function runImport(opts) {
|
|
|
3570
3592
|
"content-type": "application/json",
|
|
3571
3593
|
Authorization: `Bearer ${token}`,
|
|
3572
3594
|
},
|
|
3573
|
-
body: JSON.stringify({
|
|
3595
|
+
body: JSON.stringify({
|
|
3596
|
+
census,
|
|
3597
|
+
name: chosen,
|
|
3598
|
+
...(opts.group ? { group: opts.group } : {}),
|
|
3599
|
+
}),
|
|
3574
3600
|
}).catch(() => null);
|
|
3575
3601
|
if (!res || !res.ok) {
|
|
3576
3602
|
const detail = res
|
|
@@ -3602,6 +3628,15 @@ export async function runImport(opts) {
|
|
|
3602
3628
|
console.log("");
|
|
3603
3629
|
console.log(section("Your system exists"));
|
|
3604
3630
|
console.log(body(`${paint.strong(payload?.name ?? "Your system")} - v1 mirrors your tokens exactly, nothing improved yet.`));
|
|
3631
|
+
/**
|
|
3632
|
+
* ONDE ELE NASCEU, dito pela plataforma e não pelo que foi pedido.
|
|
3633
|
+
*
|
|
3634
|
+
* A flag carrega um nome falado e o casamento acontece do outro lado, então imprimir o que foi
|
|
3635
|
+
* pedido provaria nada. Este é o campo que o dono não teve em 20/08, quando dois sistemas
|
|
3636
|
+
* nasceram no espaço pessoal dele e o grupo ficou vazio.
|
|
3637
|
+
*/
|
|
3638
|
+
if (payload?.group)
|
|
3639
|
+
console.log(body(paint.dim(`In the group ${payload.group}.`)));
|
|
3605
3640
|
for (const note of payload?.notes ?? [])
|
|
3606
3641
|
console.log(body(paint.dim(note)));
|
|
3607
3642
|
// What a v2 would be worth, in their own values. Said here because this is
|
|
@@ -106,15 +106,77 @@ export function describeArchitecture(a) {
|
|
|
106
106
|
* open one component. And `fact: true`, because it was read off their directories: it is
|
|
107
107
|
* true once, not a habit that needs a third sighting.
|
|
108
108
|
*/
|
|
109
|
-
export function architectureRule(a
|
|
109
|
+
export function architectureRule(a,
|
|
110
|
+
/**
|
|
111
|
+
* O ESCOPO, para a regra dizer um caminho que existe. `a.root` é relativo ao escopo, e uma
|
|
112
|
+
* regra no CLAUDE.md de um monorepo que diz `src/lib/SignalUI` manda o agente para um caminho
|
|
113
|
+
* que não resolve da raiz - o mesmo defeito que fez o dono reprovar as opções da pergunta.
|
|
114
|
+
*/
|
|
115
|
+
scope) {
|
|
116
|
+
const home = componentHome(a, scope);
|
|
110
117
|
return {
|
|
111
|
-
text: describeArchitecture(a)
|
|
118
|
+
text: `${describeArchitecture(a)} A new component goes under \`${home}\`.`,
|
|
112
119
|
applies: [],
|
|
113
120
|
kind: "implementation",
|
|
114
121
|
fact: true,
|
|
115
|
-
evidence: `${a.evidence.join("/")} under ${a.root}, holding ${a.files} component file${a.files === 1 ? "" : "s"}`,
|
|
122
|
+
evidence: `${a.evidence.join("/")} under ${scope ? `${scope}/${a.root}` : a.root}, holding ${a.files} component file${a.files === 1 ? "" : "s"}`,
|
|
116
123
|
};
|
|
117
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* ONDE UM COMPONENTE NOVO VAI, ESCRITO COMO CAMINHO - e o caminho é a resposta.
|
|
127
|
+
*
|
|
128
|
+
* O dono leu esta pergunta na tela em 20/08 e a reprovou por uma razão que a versão
|
|
129
|
+
* anterior não tinha como resolver: *"'manter a escada atômica' não responde onde nasce
|
|
130
|
+
* o componente"*. O título de cada opção era o NOME DO PADRÃO e a árvore estava enterrada
|
|
131
|
+
* numa descrição de quatro linhas - então a pergunta pedia uma decisão de organização e
|
|
132
|
+
* mostrava um glossário.
|
|
133
|
+
*
|
|
134
|
+
* A resposta a "onde" é um caminho. Então o caminho é o título, ele vem daqui pronto, e
|
|
135
|
+
* ele é COMPLETO a partir da raiz do repositório: `src/lib/SignalUI` sem o `packages/ui/`
|
|
136
|
+
* na frente é ambíguo num monorepo, e é para o CLAUDE.md que essa linha vai.
|
|
137
|
+
*/
|
|
138
|
+
export function componentHome(a, scope) {
|
|
139
|
+
const base = scope ? `${scope.replace(/\/+$/, "")}/${a.root}` : a.root;
|
|
140
|
+
const tidy = base.replace(/\/\.$/, "").replace(/^\.\//, "");
|
|
141
|
+
return a.evidence.length > 0 ? `${tidy}/{${a.evidence.join(", ")}}` : tidy;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* A MESMA FORMA EM UMA FRASE - o que decide, e o número que a torna credível.
|
|
145
|
+
*
|
|
146
|
+
* `describeArchitecture` continua existindo e continua longo: ele é a REGRA que vai para
|
|
147
|
+
* o CLAUDE.md, onde um agente precisa do critério inteiro. Numa lista de opções esse
|
|
148
|
+
* mesmo texto é o que faz três linhas viraram doze e ninguém ler nenhuma.
|
|
149
|
+
*/
|
|
150
|
+
const LINES = {
|
|
151
|
+
atomic: (a) => `A rung per what it composes - atom, molecule, organism. ${a.files} files already here.`,
|
|
152
|
+
feature: (a) => `Beside the feature that uses it; it moves up only when a second one needs it. ${a.files} files.`,
|
|
153
|
+
layered: (a) => `By layer - ui, hooks, utils - not by feature. ${a.files} files already here.`,
|
|
154
|
+
flat: (a) => `One folder deep, no ladder. Legible while the system is small. ${a.files} files.`,
|
|
155
|
+
colocated: (a) => `Beside the route that renders it, shared only when a second page needs it. ${a.files} files.`,
|
|
156
|
+
};
|
|
157
|
+
export function homeLine(a) {
|
|
158
|
+
return LINES[a.kind](a);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* UMA PASTA NOVA, PROPOSTA - a opção que faltava, e o dono pediu por ela.
|
|
162
|
+
*
|
|
163
|
+
* As opções eram todas retratos: manter isto, manter aquilo. Nenhuma deixava alguém dizer
|
|
164
|
+
* *"daqui em diante vai num lugar novo"*, que é uma resposta legítima e frequente - e sem
|
|
165
|
+
* ela a pergunta é sobre o passado.
|
|
166
|
+
*
|
|
167
|
+
* O caminho é DERIVADO, não inventado: fica dentro do escopo que a pessoa já apontou como
|
|
168
|
+
* fonte de verdade, e usa `src/` só quando as formas medidas mostram que o escopo tem `src`.
|
|
169
|
+
* Sem nome de sistema dentro dele de propósito - quem quer isso digita, e digitar um nome
|
|
170
|
+
* é mais honesto do que a gente adivinhar a grafia dele.
|
|
171
|
+
*/
|
|
172
|
+
export function proposeNewHome(found, scope) {
|
|
173
|
+
const base = scope ? scope.replace(/\/+$/, "") : "";
|
|
174
|
+
const hasSrc = found.some((a) => a.root === "src" || a.root.startsWith("src/"));
|
|
175
|
+
const trunk = `${base ? `${base}/` : ""}${hasSrc ? "src/components" : "components"}`;
|
|
176
|
+
const fresh = `${trunk}/{atoms, molecules, organisms}`;
|
|
177
|
+
/** Se a proposta é o que já existe, ela não é uma pasta nova - e oferecê-la seria repetir a opção 1. */
|
|
178
|
+
return found.some((a) => componentHome(a, scope) === fresh) ? null : fresh;
|
|
179
|
+
}
|
|
118
180
|
/**
|
|
119
181
|
* A ESTRUTURA, ESCRITA - as pastas que a forma tem, na ordem em que ela as usa.
|
|
120
182
|
*
|
package/dist/index.js
CHANGED
|
@@ -88,7 +88,11 @@ Options:
|
|
|
88
88
|
--dir <path> consumer project root (default: current directory)
|
|
89
89
|
--version <n> install a specific version (default: latest)
|
|
90
90
|
--ds <slug> init: bring this DS in right away · generate: target DS (default: installed)
|
|
91
|
-
--name <name>
|
|
91
|
+
--name <name> import: the NAME of the system, which is what its install slug
|
|
92
|
+
comes from - and the slug never changes. Also the preferred
|
|
93
|
+
component name for generate.
|
|
94
|
+
--group <name> import: the GROUP it is born in, by name ("--group SignalUI").
|
|
95
|
+
Without it the system lands in your own space.
|
|
92
96
|
--scope <path> import: the SYSTEM - tokens, components, convention. Repeatable;
|
|
93
97
|
the first one wins a tie.
|
|
94
98
|
--usage <path> import: the EVIDENCE - counts, chosen values, laws. Repeatable.
|
|
@@ -158,6 +162,14 @@ async function main() {
|
|
|
158
162
|
dry: flags.dry === true,
|
|
159
163
|
census: typeof flags.census === "string" ? flags.census : undefined,
|
|
160
164
|
name: typeof flags.name === "string" ? flags.name : undefined,
|
|
165
|
+
/**
|
|
166
|
+
* EM QUAL GRUPO ELE NASCE - o nome, como a pessoa o fala.
|
|
167
|
+
*
|
|
168
|
+
* Sem a flag, no espaço pessoal (o padrão de sempre). Com ela, no grupo que ela nomeou -
|
|
169
|
+
* e um nome que a plataforma não reconhece RECUSA o envio em vez de cair no pessoal, que
|
|
170
|
+
* é o desvio que ninguém percebe até ir procurar o sistema.
|
|
171
|
+
*/
|
|
172
|
+
group: typeof flags.group === "string" ? flags.group : undefined,
|
|
161
173
|
// Only these two words. Anything else is a typo that would silently
|
|
162
174
|
// invert a system, so it falls through to being measured and asked.
|
|
163
175
|
// WHAT to read. `--dir` stays WHERE the project is, in every command.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { anatomyFromSketch } from "./anatomy-from-sketch.js";
|
|
2
|
+
/** O nó que a derivação não soube nomear. `box` é o último recurso dela. */
|
|
3
|
+
const UNNAMED = "box";
|
|
4
|
+
function walk(read, onNode) {
|
|
5
|
+
for (const node of read) {
|
|
6
|
+
onNode(node);
|
|
7
|
+
if (Array.isArray(node.children) && node.children.length > 0)
|
|
8
|
+
walk(node.children, onNode);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A fila, derivada dos mesmos insumos que o envio usa.
|
|
13
|
+
*
|
|
14
|
+
* `defines` e `versionOf` entram porque a derivação os usa para distinguir um componente DELES de
|
|
15
|
+
* uma peça de terceiro, e um nó que vira `component` ou `external` é um nó nomeado: computar a fila
|
|
16
|
+
* sem eles a inflaria com trabalho que não existe.
|
|
17
|
+
*/
|
|
18
|
+
export function namingQueue(looks, defines, versionOf) {
|
|
19
|
+
const pending = [];
|
|
20
|
+
let components = 0;
|
|
21
|
+
let nodes = 0;
|
|
22
|
+
let named = 0;
|
|
23
|
+
let settled = 0;
|
|
24
|
+
for (const component of Object.keys(looks)) {
|
|
25
|
+
const sketch = looks[component]?.sketch;
|
|
26
|
+
if (!Array.isArray(sketch) || sketch.length === 0)
|
|
27
|
+
continue;
|
|
28
|
+
const derived = anatomyFromSketch(sketch, defines, versionOf);
|
|
29
|
+
if (derived.read.length === 0)
|
|
30
|
+
continue;
|
|
31
|
+
components += 1;
|
|
32
|
+
const unnamed = [];
|
|
33
|
+
walk(derived.read, (node) => {
|
|
34
|
+
nodes += 1;
|
|
35
|
+
if (node.name !== UNNAMED) {
|
|
36
|
+
named += 1;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const at = node.at;
|
|
40
|
+
if (typeof at !== "number")
|
|
41
|
+
return;
|
|
42
|
+
const raw = sketch[at];
|
|
43
|
+
unnamed.push({
|
|
44
|
+
tag: raw?.tag ?? "div",
|
|
45
|
+
at,
|
|
46
|
+
...(raw?.classes ? { classes: raw.classes } : {}),
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
if (unnamed.length === 0) {
|
|
50
|
+
settled += 1;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
pending.push({ component, nodes: unnamed });
|
|
54
|
+
}
|
|
55
|
+
return { components, nodes, named, settled, pending };
|
|
56
|
+
}
|
package/package.json
CHANGED