synthesisui 0.16.290 → 0.16.292
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/align.js +16 -1
- package/dist/commands/generate.js +2 -12
- package/dist/commands/import.js +39 -0
- package/dist/commands/refit.js +2 -24
- package/dist/doctor/broken-refs.js +43 -2
- package/dist/index.js +37 -6
- package/dist/install-marks.js +1 -1
- package/dist/installed.js +68 -0
- package/package.json +1 -1
package/dist/commands/align.js
CHANGED
|
@@ -579,8 +579,23 @@ export async function nextStepFor(root) {
|
|
|
579
579
|
if (locks.length > 0)
|
|
580
580
|
return null;
|
|
581
581
|
const measured = await readFile(join(root, "_synthesisui", "census.json"), "utf8").then(() => true, () => false);
|
|
582
|
+
/**
|
|
583
|
+
* MEDIDO E SEM SISTEMA INSTALADO SÃO DUAS HISTÓRIAS, e a frase antiga contava a errada.
|
|
584
|
+
*
|
|
585
|
+
* Ela dizia *"continue the import"*, e em 23/08 foi exatamente o que o agente fez: mediu o
|
|
586
|
+
* repositório inteiro de novo, refez a leitura, reenviou. O sistema JÁ EXISTIA na conta dele - o
|
|
587
|
+
* que faltava eram os arquivos aqui, e `add` é o comando que os traz. Medir de novo custou sete
|
|
588
|
+
* minutos e não mudou nada do que a plataforma sabia.
|
|
589
|
+
*
|
|
590
|
+
* As duas situações que produzem este estado, e as duas terminam no mesmo comando: um import que
|
|
591
|
+
* criou o sistema e parou antes de instalar (o que este CLI já não faz - ver o fim de `runImport`),
|
|
592
|
+
* e um clone fresco de um repositório onde alguém apagou a pasta `ds/`.
|
|
593
|
+
*
|
|
594
|
+
* `list --mine` primeiro porque o slug nasce no servidor: ele não está em nenhum arquivo daqui, e
|
|
595
|
+
* chutá-lo seria pior que pedir para olhar.
|
|
596
|
+
*/
|
|
582
597
|
return measured
|
|
583
|
-
?
|
|
598
|
+
? "This repo has been measured and has no system installed here. If you already imported, the system is in your account: `synthesisui list --mine`, then `synthesisui add <slug>`."
|
|
584
599
|
: 'This repo has no design system contract yet. Ask me: "import my design system."';
|
|
585
600
|
}
|
|
586
601
|
/**
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { mkdir,
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { generateComponentFiles } from "../component-codegen.js";
|
|
4
4
|
import { readProjectConfig, resolveRegistry } from "../config.js";
|
|
5
|
+
import { installedSlugs } from "../installed.js";
|
|
5
6
|
import { reactMajorOf, readInstalledConvention, readInstalledScheme, } from "../project-facts.js";
|
|
6
7
|
import { postGenerate, RegistryError } from "../registry.js";
|
|
7
8
|
/** PascalCase para o hint de import (course-card → CourseCard). */
|
|
@@ -20,17 +21,6 @@ async function readActiveVersion(root, slug) {
|
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
23
|
/** Slugs materialized under `_synthesisui/ds/` in the project. */
|
|
23
|
-
async function installedSlugs(root) {
|
|
24
|
-
try {
|
|
25
|
-
const entries = await readdir(join(root, "_synthesisui", "ds"), {
|
|
26
|
-
withFileTypes: true,
|
|
27
|
-
});
|
|
28
|
-
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
return [];
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
24
|
/**
|
|
35
25
|
* Generates a token-only component recipe for the project's design system
|
|
36
26
|
* (chat-gen PRO, hosted) and materializes it additively under
|
package/dist/commands/import.js
CHANGED
|
@@ -49,6 +49,7 @@ import { phase, startProgress } from "../progress.js";
|
|
|
49
49
|
import { repoStateOf } from "../repo-state.js";
|
|
50
50
|
import { detectStack, resolveDeps, stackVersions } from "../stack.js";
|
|
51
51
|
import { placeInWorkspace } from "../workspace-place.js";
|
|
52
|
+
import { add } from "./add.js";
|
|
52
53
|
import { walk, walkAll } from "./doctor.js";
|
|
53
54
|
/**
|
|
54
55
|
* How many distinct values travel, PER KIND.
|
|
@@ -3942,4 +3943,42 @@ export async function runImport(opts) {
|
|
|
3942
3943
|
if (payload?.url)
|
|
3943
3944
|
console.log(body(` ${paint.blue(payload.url)}`));
|
|
3944
3945
|
console.log("");
|
|
3946
|
+
/**
|
|
3947
|
+
* E O SISTEMA CHEGA NO REPOSITÓRIO DELE - quem manda importar quer usar.
|
|
3948
|
+
*
|
|
3949
|
+
* O QUE ELE VIVEU TRÊS VEZES EM 23/08: mandou importar, viu o sistema no ar com uma URL, e
|
|
3950
|
+
* concluiu que tinha acabado. O repositório ficava com o censo, o ledger e o relatório de
|
|
3951
|
+
* lacunas - sem `ds/`, sem `.lock`, sem `tokens.css`. O agente dele não sabia que o design
|
|
3952
|
+
* system existia, e o comando seguinte falhava com "no design system installed here". E nada
|
|
3953
|
+
* dizia que faltava um passo: nem o fim do import, nem a skill (que não cita `add` uma vez),
|
|
3954
|
+
* nem o `doctor`.
|
|
3955
|
+
*
|
|
3956
|
+
* A LINHA "não escrevemos sem pedir" já foi cruzada aqui: este comando escreve o censo, o
|
|
3957
|
+
* ledger, o `not-expressed.md` e um `.gitignore`. Parar antes de instalar não protegia nada -
|
|
3958
|
+
* interrompia. Quem quer olhar antes de escrever usa `--dry`, que retorna muito acima desta
|
|
3959
|
+
* linha e é onde essa responsabilidade mora.
|
|
3960
|
+
*
|
|
3961
|
+
* E É AQUI, DEPOIS DO RESUMO, e não antes: o resumo é sobre o que a leitura encontrou, e a
|
|
3962
|
+
* instalação é sobre o que passou a existir na máquina dele. Misturar as duas faria a saída
|
|
3963
|
+
* mais longa do produto ficar mais longa no lugar onde ela já é mais difícil de ler.
|
|
3964
|
+
*/
|
|
3965
|
+
if (payload?.slug) {
|
|
3966
|
+
try {
|
|
3967
|
+
await add(payload.slug, {
|
|
3968
|
+
registry: opts.registry,
|
|
3969
|
+
dir: root,
|
|
3970
|
+
});
|
|
3971
|
+
}
|
|
3972
|
+
catch (error) {
|
|
3973
|
+
/**
|
|
3974
|
+
* O SISTEMA FOI CRIADO NO SERVIDOR, e isso não se desfaz. Uma rede que cai na materialização
|
|
3975
|
+
* custa os arquivos locais e nada mais - então o comando diz o que rodar, e jamais devolve
|
|
3976
|
+
* um erro que faria a pessoa achar que perdeu a medição.
|
|
3977
|
+
*/
|
|
3978
|
+
console.log("");
|
|
3979
|
+
console.log(body(`Your system exists, and the files did not land here: ${error instanceof Error ? error.message : String(error)}`));
|
|
3980
|
+
console.log(body(` synthesisui add ${payload.slug}`));
|
|
3981
|
+
console.log("");
|
|
3982
|
+
}
|
|
3983
|
+
}
|
|
3945
3984
|
}
|
package/dist/commands/refit.js
CHANGED
|
@@ -1,35 +1,13 @@
|
|
|
1
|
-
import { access, mkdir,
|
|
1
|
+
import { access, mkdir, 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
|
+
import { installedSlugs } from "../installed.js";
|
|
5
6
|
import { body, section, snippet } from "../output.js";
|
|
6
7
|
import { reactMajorOf, readInstalledConvention, readInstalledScheme, } from "../project-facts.js";
|
|
7
8
|
import { fetchComponent, postRefit, postSaveComponent, RegistryError, } from "../registry.js";
|
|
8
9
|
/** Slugs INSTALLED under `_synthesisui/ds/` (a `.lock` marks a real install -
|
|
9
10
|
* a folder holding only refit artifacts doesn't count). */
|
|
10
|
-
async function installedSlugs(root) {
|
|
11
|
-
try {
|
|
12
|
-
const entries = await readdir(join(root, "_synthesisui", "ds"), {
|
|
13
|
-
withFileTypes: true,
|
|
14
|
-
});
|
|
15
|
-
const slugs = [];
|
|
16
|
-
for (const entry of entries) {
|
|
17
|
-
if (!entry.isDirectory())
|
|
18
|
-
continue;
|
|
19
|
-
try {
|
|
20
|
-
await access(join(root, "_synthesisui", "ds", entry.name, ".lock"));
|
|
21
|
-
slugs.push(entry.name);
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
// artifacts-only folder (e.g. a refit before `add`) - not installed
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return slugs;
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return [];
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
11
|
/** True when the system is actually installed (tokens.css present). */
|
|
34
12
|
async function isInstalled(root, slug) {
|
|
35
13
|
try {
|
|
@@ -21,8 +21,26 @@ import { frontierKind } from "../frontier-kind.js";
|
|
|
21
21
|
import { importMap } from "./imports.js";
|
|
22
22
|
/** Quantos lugares viajam por referência quebrada. Ver `BrokenRef.at`. */
|
|
23
23
|
const MAX_PLACES = 3;
|
|
24
|
-
/**
|
|
25
|
-
|
|
24
|
+
/**
|
|
25
|
+
* `var(--x)`, including inside a Tailwind arbitrary value: `bg-[var(--x)]`.
|
|
26
|
+
*
|
|
27
|
+
* O SEGUNDO GRUPO É O FALLBACK, e é ele que separa uma referência quebrada de uma com rede:
|
|
28
|
+
* `var(--aurora-angle,125deg)` pinta 125deg. Chamar isso de "não pinta nada" é dizer ao cliente que
|
|
29
|
+
* o código dele está defeituoso quando ele escreveu a defesa.
|
|
30
|
+
*/
|
|
31
|
+
const VAR_REF = /var\(\s*(--[a-zA-Z0-9_-]+)\s*(,)?/g;
|
|
32
|
+
/**
|
|
33
|
+
* `el.style.setProperty("--tx", …)` - uma custom property DECLARADA em JavaScript.
|
|
34
|
+
*
|
|
35
|
+
* O QUE O CLIENTE RECEBIA SEM ISTO: `--tx` e `--ty` na lista de "referências que não pintam nada",
|
|
36
|
+
* quando um hook de tilt dele as escreve a cada movimento do mouse. O agente dele diagnosticou isso à
|
|
37
|
+
* mão em 23/08 e disse a frase que virou esta regra: *"o que um leitor não consegue ver é uma custom
|
|
38
|
+
* property escrita por JS"*. A resposta não é adivinhar - é procurar a escrita, e ela é literal.
|
|
39
|
+
*
|
|
40
|
+
* Medido em quatro populações: 2 nomes no `codelevel-ui`, 0 no `packages/ui` do `frontend-hub`, 2 no
|
|
41
|
+
* dashboard dele e 3 no nosso próprio app. Três de quatro escrevem variável por JS.
|
|
42
|
+
*/
|
|
43
|
+
const SET_PROPERTY = /setProperty\(\s*['"`](--[a-zA-Z0-9_-]+)/g;
|
|
26
44
|
/**
|
|
27
45
|
* VARIABLES A HEADLESS LIBRARY SETS AT RUNTIME, which no stylesheet can declare.
|
|
28
46
|
*
|
|
@@ -90,12 +108,35 @@ const NAMESPACES = [
|
|
|
90
108
|
*/
|
|
91
109
|
export function findBrokenRefs(sources, declared) {
|
|
92
110
|
const seen = new Map();
|
|
111
|
+
/**
|
|
112
|
+
* AS QUE O PRÓPRIO CÓDIGO DELE ESCREVE EM JAVASCRIPT - ver `SET_PROPERTY`.
|
|
113
|
+
*
|
|
114
|
+
* Colhidas de TODAS as fontes antes do laço, e não por arquivo: quem escreve `--tx` é o hook, e
|
|
115
|
+
* quem a lê é a folha global. São dois arquivos, e perguntar por arquivo diria que a folha
|
|
116
|
+
* referencia algo que ninguém declara.
|
|
117
|
+
*/
|
|
118
|
+
const setInJs = new Set();
|
|
119
|
+
for (const { source } of sources)
|
|
120
|
+
for (const m of source.matchAll(SET_PROPERTY))
|
|
121
|
+
setInJs.add(m[1]);
|
|
93
122
|
for (const { file, source } of sources) {
|
|
94
123
|
const runtime = importsHeadless(source);
|
|
95
124
|
for (const m of source.matchAll(VAR_REF)) {
|
|
96
125
|
const name = m[1];
|
|
97
126
|
if (declared.has(name))
|
|
98
127
|
continue;
|
|
128
|
+
/**
|
|
129
|
+
* UMA CHAMADA COM FALLBACK NÃO ESTÁ QUEBRADA - ela pinta o fallback.
|
|
130
|
+
*
|
|
131
|
+
* Por CHAMADA e não por nome: a mesma variável pode ser lida com rede num lugar e sem rede em
|
|
132
|
+
* outro, e é a segunda que precisa de conserto. Contar as duas juntas ou descartar as duas
|
|
133
|
+
* juntas erra em direções opostas.
|
|
134
|
+
*/
|
|
135
|
+
if (m[2])
|
|
136
|
+
continue;
|
|
137
|
+
/** Declarada em JS - só não em CSS. Ver `SET_PROPERTY`. */
|
|
138
|
+
if (setInJs.has(name))
|
|
139
|
+
continue;
|
|
99
140
|
if (runtime && (RUNTIME_ANCHOR.has(name) || RUNTIME_PREFIX.test(name)))
|
|
100
141
|
continue;
|
|
101
142
|
const hit = seen.get(name) ?? {
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ import { template } from "./commands/template.js";
|
|
|
30
30
|
import { upgrade } from "./commands/upgrade.js";
|
|
31
31
|
import { use } from "./commands/use.js";
|
|
32
32
|
import { appendEvent } from "./doctor/ledger.js";
|
|
33
|
+
import { blueprintTarget, installedSlugs } from "./installed.js";
|
|
33
34
|
import { RegistryError } from "./registry.js";
|
|
34
35
|
/** Our own version, for pinning the hook and MCP commands we write into a
|
|
35
36
|
* project. Read from the package we are running out of, so a pinned command
|
|
@@ -44,8 +45,10 @@ Usage - deterministic, FREE:
|
|
|
44
45
|
synthesisui list [options] list the published design systems
|
|
45
46
|
synthesisui list --mine your own systems, with their group
|
|
46
47
|
synthesisui add <slug> [options] materialize a DS into _synthesisui/ds/<slug>/
|
|
47
|
-
synthesisui
|
|
48
|
-
|
|
48
|
+
synthesisui bp <name> bring one EXISTING blueprint in as YOUR <Pascal>.tsx
|
|
49
|
+
(the slug is optional - this repo's system answers for it)
|
|
50
|
+
synthesisui bp <slug> <name> the same, from another system
|
|
51
|
+
synthesisui blueprint | component the same command, spelled in full
|
|
49
52
|
synthesisui template <slug> <name> materialize a whole page from a DS template
|
|
50
53
|
(--as landing-home names the output - multi-page safe)
|
|
51
54
|
synthesisui upgrade <slug> update an installed DS + regenerate your components + migration brief
|
|
@@ -468,14 +471,42 @@ async function main() {
|
|
|
468
471
|
* que apelido nenhum.
|
|
469
472
|
*/
|
|
470
473
|
case "bp":
|
|
474
|
+
case "blueprint":
|
|
471
475
|
case "component": {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
+
/**
|
|
477
|
+
* O SLUG É OPCIONAL, e o repositório responde por ele.
|
|
478
|
+
*
|
|
479
|
+
* `synthesisui bp card` num repositório que tem UM sistema instalado é a forma que a pessoa
|
|
480
|
+
* escreve naturalmente - ela está dentro do projeto, o sistema dela é aquele, e repetir o nome
|
|
481
|
+
* dele é a plataforma pedindo uma informação que ela já tem no disco.
|
|
482
|
+
*
|
|
483
|
+
* COM DOIS ARGUMENTOS o primeiro é o slug, que é o comportamento de sempre e o que permite
|
|
484
|
+
* trazer um blueprint de OUTRO sistema para cá.
|
|
485
|
+
*
|
|
486
|
+
* E O CASO AMBÍGUO É RECUSADO EM VEZ DE ADIVINHADO: um argumento só que é exatamente o nome do
|
|
487
|
+
* sistema instalado - `synthesisui bp codelevel-ds` - é o erro que o comentário acima registra,
|
|
488
|
+
* e ele tem duas leituras opostas ("instale este sistema" / "materialize um blueprint chamado
|
|
489
|
+
* codelevel-ds"). Escolher uma em silêncio seria acertar metade das vezes.
|
|
490
|
+
*/
|
|
491
|
+
const root = dir ?? process.cwd();
|
|
492
|
+
const installed = await installedSlugs(root);
|
|
493
|
+
const target = blueprintTarget({
|
|
494
|
+
args: [args[0], args[1]],
|
|
495
|
+
local: installed.length === 1 ? installed[0] : null,
|
|
496
|
+
installed,
|
|
497
|
+
});
|
|
498
|
+
if ("error" in target) {
|
|
499
|
+
console.error(target.error === "ambiguous"
|
|
500
|
+
? `error: "${target.name}" is the system installed here, not a blueprint name - say which blueprint you want: \`synthesisui bp <name>\``
|
|
501
|
+
: target.error === "no-name"
|
|
502
|
+
? "error: provide a blueprint name - `synthesisui bp <name>`, or `synthesisui bp <slug> <name>` for another system"
|
|
503
|
+
: target.error === "no-system"
|
|
504
|
+
? "error: no design system installed here - run `synthesisui add <slug>` first, or name one: `synthesisui bp <slug> <name>`"
|
|
505
|
+
: `error: ${installed.length} systems installed here (${installed.join(", ")}) - say which: \`synthesisui bp <slug> <name>\``);
|
|
476
506
|
process.exitCode = 1;
|
|
477
507
|
return;
|
|
478
508
|
}
|
|
509
|
+
const { slug, name } = target;
|
|
479
510
|
let version;
|
|
480
511
|
if (typeof flags.version === "string") {
|
|
481
512
|
version = Number.parseInt(flags.version.replace(/^v/i, ""), 10);
|
package/dist/install-marks.js
CHANGED
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
* é sempre o bump deste PR - nunca o número que o `package.json` já carrega, porque alguém pode
|
|
129
129
|
* publicar no meio.
|
|
130
130
|
*/
|
|
131
|
-
export const MATERIALISER_SINCE = "0.16.
|
|
131
|
+
export const MATERIALISER_SINCE = "0.16.292";
|
|
132
132
|
/**
|
|
133
133
|
* A ÚLTIMA VERSÃO EM QUE O QUE O HOOK RODA MUDOU.
|
|
134
134
|
*
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { access, readdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* QUAIS SISTEMAS ESTÃO INSTALADOS NESTE REPOSITÓRIO - um lugar só, e a resposta certa.
|
|
5
|
+
*
|
|
6
|
+
* ESTA FUNÇÃO EXISTIA DUAS VEZES, em `refit.ts` e `generate.ts`, e elas discordavam: a primeira
|
|
7
|
+
* exigia o `.lock` - o arquivo que prova que o `add` rodou - e a segunda listava a pasta. Uma pasta
|
|
8
|
+
* `ds/<slug>/` existe assim que qualquer comando escreve um artefato ali, então o `generate`
|
|
9
|
+
* enxergava como instalado um sistema que ainda não tinha nada materializado, e a mensagem que ele
|
|
10
|
+
* daria ao cliente seria sobre um sistema que ele não pode usar.
|
|
11
|
+
*
|
|
12
|
+
* O `.lock` é o portão porque ele é o que o `add` escreve por último: se ele está lá, os arquivos
|
|
13
|
+
* estão. Ver `RootLock` em `add.ts`.
|
|
14
|
+
*
|
|
15
|
+
* E COM ISTO O SLUG PASSA A SER OPCIONAL nos comandos que agem sobre um sistema. Quem está num
|
|
16
|
+
* repositório que tem um sistema instalado não deveria precisar repetir o nome dele - o repositório
|
|
17
|
+
* já sabe.
|
|
18
|
+
*/
|
|
19
|
+
export async function installedSlugs(root) {
|
|
20
|
+
try {
|
|
21
|
+
const dsDir = join(root, "_synthesisui", "ds");
|
|
22
|
+
const entries = await readdir(dsDir, { withFileTypes: true });
|
|
23
|
+
const slugs = [];
|
|
24
|
+
for (const entry of entries) {
|
|
25
|
+
if (!entry.isDirectory())
|
|
26
|
+
continue;
|
|
27
|
+
try {
|
|
28
|
+
await access(join(dsDir, entry.name, ".lock"));
|
|
29
|
+
slugs.push(entry.name);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// pasta de artefato (um refit antes do `add`, por exemplo) - não é um install
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return slugs.sort();
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* O SISTEMA DESTE REPOSITÓRIO, quando há exatamente um - e `null` quando a pergunta não tem resposta.
|
|
43
|
+
*
|
|
44
|
+
* Nenhum instalado e dois instalados são situações diferentes com a mesma consequência: a plataforma
|
|
45
|
+
* não pode escolher por ele. Escolher o primeiro em ordem alfabética seria a pior forma de errar -
|
|
46
|
+
* silenciosa, e correta na metade dos casos. Quem chama diz o que fazer com o `null`, e o que ele
|
|
47
|
+
* tem a dizer é diferente nos dois casos, então `installedSlugs` continua disponível para nomear os
|
|
48
|
+
* candidatos na mensagem.
|
|
49
|
+
*/
|
|
50
|
+
export async function theInstalledSlug(root) {
|
|
51
|
+
const slugs = await installedSlugs(root);
|
|
52
|
+
return slugs.length === 1 ? slugs[0] : null;
|
|
53
|
+
}
|
|
54
|
+
export function blueprintTarget(input) {
|
|
55
|
+
const [first, second] = input.args;
|
|
56
|
+
if (first && second)
|
|
57
|
+
return { slug: first, name: second };
|
|
58
|
+
const name = first;
|
|
59
|
+
if (!name)
|
|
60
|
+
return { error: "no-name" };
|
|
61
|
+
if (input.local && name === input.local)
|
|
62
|
+
return { error: "ambiguous", name };
|
|
63
|
+
if (!input.local)
|
|
64
|
+
return input.installed.length > 1
|
|
65
|
+
? { error: "many-systems" }
|
|
66
|
+
: { error: "no-system" };
|
|
67
|
+
return { slug: input.local, name };
|
|
68
|
+
}
|
package/package.json
CHANGED