advui 0.1.0
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/LICENSE +49 -0
- package/README.md +21 -0
- package/dist/commands.js +126 -0
- package/dist/config.js +21 -0
- package/dist/constants.js +14 -0
- package/dist/index.js +58 -0
- package/dist/project.js +50 -0
- package/dist/registry.js +50 -0
- package/package.json +42 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Universal UI contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
Third-party notices
|
|
26
|
+
|
|
27
|
+
Icons in packages/icons are generated from Lucide (https://lucide.dev),
|
|
28
|
+
licensed under the ISC License:
|
|
29
|
+
|
|
30
|
+
ISC License
|
|
31
|
+
Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part
|
|
32
|
+
of Feather (MIT). All other copyright (c) for Lucide are held by Lucide
|
|
33
|
+
Contributors 2022.
|
|
34
|
+
|
|
35
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
36
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
37
|
+
copyright notice and this permission notice appear in all copies.
|
|
38
|
+
|
|
39
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
40
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
41
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
42
|
+
SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
43
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
|
44
|
+
OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
45
|
+
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
46
|
+
|
|
47
|
+
Color scales in packages/theme are based on Radix Colors
|
|
48
|
+
(https://github.com/radix-ui/colors), licensed under the MIT License,
|
|
49
|
+
Copyright (c) 2022 WorkOS.
|
package/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# advui (CLI)
|
|
2
|
+
|
|
3
|
+
Copy Adv UI component source into your project, shadcn-style.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx advui init # detect framework, write config, install base packages
|
|
7
|
+
npx advui add button dialog # add components (dependencies resolved)
|
|
8
|
+
npx advui add --all
|
|
9
|
+
npx advui list
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
| Option | Description |
|
|
13
|
+
| -------------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
14
|
+
| `--registry <url or path>` | Registry to read (default: `advui.json`, then https://zinmin232.github.io/advui/r) |
|
|
15
|
+
| `--cwd <path>` | Project directory |
|
|
16
|
+
| `--framework next\|expo\|react-native\|vite` | Skip detection in `init` |
|
|
17
|
+
| `--no-install` | Print the install command instead of running it |
|
|
18
|
+
| `--overwrite` | Replace existing files |
|
|
19
|
+
|
|
20
|
+
The registry is generated from component metadata by `pnpm registry:build` in
|
|
21
|
+
the monorepo. License: MIT.
|
package/dist/commands.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, relative } from 'node:path';
|
|
4
|
+
import { defaultConfig, readConfig, writeConfig } from './config.js';
|
|
5
|
+
import { BASE_DEPENDENCIES, CLI_NAME, CONFIG_FILE, DEFAULT_REGISTRY, PACKAGE_SCOPE, PRODUCT_NAME, } from './constants.js';
|
|
6
|
+
import { detectProject, installCommand } from './project.js';
|
|
7
|
+
import { collectDependencies, fetchRegistryJson, resolveItems, } from './registry.js';
|
|
8
|
+
const frameworkPeers = {
|
|
9
|
+
next: ['react-native-web', 'react-native'],
|
|
10
|
+
expo: ['react-native-svg'],
|
|
11
|
+
'react-native': ['react-native-svg'],
|
|
12
|
+
vite: ['react-native-web', 'react-native'],
|
|
13
|
+
unknown: [],
|
|
14
|
+
};
|
|
15
|
+
const setupNotes = {
|
|
16
|
+
next: `Next.js: add to next.config.ts
|
|
17
|
+
transpilePackages: ['${PACKAGE_SCOPE}/theme', '${PACKAGE_SCOPE}/icons', '${PACKAGE_SCOPE}/utils', 'react-native-web'],
|
|
18
|
+
turbopack: { resolveAlias: { 'react-native': 'react-native-web' },
|
|
19
|
+
resolveExtensions: ['.web.tsx', '.web.ts', '.tsx', '.ts', '.jsx', '.js', '.mjs', '.json'] }
|
|
20
|
+
and wrap your root layout in a 'use client' provider that renders <UniversalProvider config={config}>.`,
|
|
21
|
+
expo: `Expo: no Metro changes needed (SDK 52+). Wrap app/_layout.tsx in <UniversalProvider config={config}>.`,
|
|
22
|
+
'react-native': `React Native: wrap your root component in <UniversalProvider config={config}>.`,
|
|
23
|
+
vite: `Vite: alias 'react-native' to 'react-native-web' and prefer '.web.tsx' extensions in vite.config.ts.`,
|
|
24
|
+
unknown: `Wrap your app root in <UniversalProvider config={config}>.`,
|
|
25
|
+
};
|
|
26
|
+
function run(command, cwd, log) {
|
|
27
|
+
log(`$ ${command}`);
|
|
28
|
+
execSync(command, { cwd, stdio: 'inherit' });
|
|
29
|
+
}
|
|
30
|
+
export async function initCommand(options) {
|
|
31
|
+
const project = detectProject(options.cwd);
|
|
32
|
+
const framework = options.framework ?? project.framework;
|
|
33
|
+
const existing = readConfig(options.cwd);
|
|
34
|
+
const config = existing ?? defaultConfig(framework, project.srcDir);
|
|
35
|
+
if (options.registry)
|
|
36
|
+
config.registry = options.registry;
|
|
37
|
+
writeConfig(options.cwd, config);
|
|
38
|
+
options.log(`${existing ? 'Updated' : 'Created'} ${CONFIG_FILE} (framework: ${framework})`);
|
|
39
|
+
const configFile = join(options.cwd, config.tamaguiConfig);
|
|
40
|
+
if (!existsSync(configFile) || options.overwrite) {
|
|
41
|
+
mkdirSync(dirname(configFile), { recursive: true });
|
|
42
|
+
writeFileSync(configFile, `import { createUniversalConfig } from '${PACKAGE_SCOPE}/theme'
|
|
43
|
+
|
|
44
|
+
// Change the preset, colors, radius or font scale — every component follows.
|
|
45
|
+
export const config = createUniversalConfig({ preset: 'indigo', radius: 'md' })
|
|
46
|
+
|
|
47
|
+
export default config
|
|
48
|
+
`);
|
|
49
|
+
options.log(`Created ${config.tamaguiConfig}`);
|
|
50
|
+
}
|
|
51
|
+
const packages = [
|
|
52
|
+
...BASE_DEPENDENCIES,
|
|
53
|
+
`${PACKAGE_SCOPE}/core`,
|
|
54
|
+
...frameworkPeers[framework],
|
|
55
|
+
].filter((pkg) => !project.dependencies[pkg]);
|
|
56
|
+
if (packages.length) {
|
|
57
|
+
const command = installCommand(project.packageManager, packages);
|
|
58
|
+
if (options.install)
|
|
59
|
+
run(command, options.cwd, options.log);
|
|
60
|
+
else
|
|
61
|
+
options.log(`Install dependencies:\n ${command}`);
|
|
62
|
+
}
|
|
63
|
+
options.log(`\n${setupNotes[framework]}\n\n${PRODUCT_NAME} is ready. Add components with: npx ${CLI_NAME} add button`);
|
|
64
|
+
}
|
|
65
|
+
export async function addCommand(names, options) {
|
|
66
|
+
const project = detectProject(options.cwd);
|
|
67
|
+
const config = readConfig(options.cwd) ?? defaultConfig(project.framework, project.srcDir);
|
|
68
|
+
const registry = options.registry ?? config.registry;
|
|
69
|
+
const load = (name) => fetchRegistryJson(registry, name, options.cwd);
|
|
70
|
+
let requested = names;
|
|
71
|
+
if (options.all) {
|
|
72
|
+
const index = await fetchRegistryJson(registry, 'index', options.cwd);
|
|
73
|
+
requested = index.items
|
|
74
|
+
.filter((item) => item.type === 'registry:component')
|
|
75
|
+
.map((item) => item.name);
|
|
76
|
+
}
|
|
77
|
+
if (!requested.length)
|
|
78
|
+
throw new Error(`Specify components, e.g. \`${CLI_NAME} add button dialog\``);
|
|
79
|
+
const items = await resolveItems(requested, load);
|
|
80
|
+
const written = [];
|
|
81
|
+
const skipped = [];
|
|
82
|
+
for (const item of items) {
|
|
83
|
+
for (const file of item.files) {
|
|
84
|
+
const target = join(options.cwd, config.uiDir, file.path);
|
|
85
|
+
if (existsSync(target) && !options.overwrite) {
|
|
86
|
+
skipped.push(relative(options.cwd, target));
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
90
|
+
writeFileSync(target, file.content);
|
|
91
|
+
written.push(relative(options.cwd, target));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
options.log(`Added ${items.map((i) => i.name).join(', ')}`);
|
|
95
|
+
for (const file of written)
|
|
96
|
+
options.log(` + ${file}`);
|
|
97
|
+
if (skipped.length)
|
|
98
|
+
options.log(`Skipped ${skipped.length} existing file(s) (use --overwrite).`);
|
|
99
|
+
const missing = collectDependencies(items).filter((pkg) => !project.dependencies[pkg]);
|
|
100
|
+
if (missing.length) {
|
|
101
|
+
const command = installCommand(project.packageManager, missing);
|
|
102
|
+
if (options.install)
|
|
103
|
+
run(command, options.cwd, options.log);
|
|
104
|
+
else
|
|
105
|
+
options.log(`Install dependencies:\n ${command}`);
|
|
106
|
+
}
|
|
107
|
+
return { items, written, skipped };
|
|
108
|
+
}
|
|
109
|
+
export async function listCommand(options) {
|
|
110
|
+
const project = (() => {
|
|
111
|
+
try {
|
|
112
|
+
return detectProject(options.cwd);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
})();
|
|
118
|
+
const config = project ? readConfig(options.cwd) : null;
|
|
119
|
+
// Listing needs no project, so fall back to the published registry.
|
|
120
|
+
const registry = options.registry ?? config?.registry ?? DEFAULT_REGISTRY;
|
|
121
|
+
const index = await fetchRegistryJson(registry, 'index', options.cwd);
|
|
122
|
+
for (const item of index.items) {
|
|
123
|
+
options.log(`${item.name.padEnd(16)} ${(item.status ?? '').padEnd(8)} ${item.description}`);
|
|
124
|
+
}
|
|
125
|
+
return index;
|
|
126
|
+
}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { CONFIG_FILE, DEFAULT_REGISTRY } from './constants.js';
|
|
4
|
+
export function defaultConfig(framework, srcDir) {
|
|
5
|
+
return {
|
|
6
|
+
$schema: 'https://zinmin232.github.io/advui/schema/config.json',
|
|
7
|
+
framework,
|
|
8
|
+
uiDir: srcDir ? 'src/ui' : 'ui',
|
|
9
|
+
registry: DEFAULT_REGISTRY,
|
|
10
|
+
tamaguiConfig: srcDir ? 'src/tamagui.config.ts' : 'tamagui.config.ts',
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function readConfig(root) {
|
|
14
|
+
const file = join(root, CONFIG_FILE);
|
|
15
|
+
if (!existsSync(file))
|
|
16
|
+
return null;
|
|
17
|
+
return JSON.parse(readFileSync(file, 'utf8'));
|
|
18
|
+
}
|
|
19
|
+
export function writeConfig(root, config) {
|
|
20
|
+
writeFileSync(join(root, CONFIG_FILE), `${JSON.stringify(config, null, 2)}\n`);
|
|
21
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Branding lives here so the project can be renamed in one place (see scripts/rename.mjs).
|
|
2
|
+
export const PRODUCT_NAME = 'Adv UI';
|
|
3
|
+
export const CLI_NAME = 'advui';
|
|
4
|
+
export const PACKAGE_SCOPE = '@advui';
|
|
5
|
+
export const CONFIG_FILE = 'advui.json';
|
|
6
|
+
/** Default remote registry. Override with `--registry` or the config file. */
|
|
7
|
+
export const DEFAULT_REGISTRY = 'https://zinmin232.github.io/advui/r';
|
|
8
|
+
/** Packages every project needs, regardless of which components are added. */
|
|
9
|
+
export const BASE_DEPENDENCIES = [
|
|
10
|
+
`${PACKAGE_SCOPE}/theme`,
|
|
11
|
+
`${PACKAGE_SCOPE}/icons`,
|
|
12
|
+
`${PACKAGE_SCOPE}/utils`,
|
|
13
|
+
'tamagui',
|
|
14
|
+
];
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from 'node:util';
|
|
3
|
+
import { addCommand, initCommand, listCommand } from './commands.js';
|
|
4
|
+
import { CLI_NAME, DEFAULT_REGISTRY, PRODUCT_NAME } from './constants.js';
|
|
5
|
+
const help = `${PRODUCT_NAME} CLI
|
|
6
|
+
|
|
7
|
+
Usage
|
|
8
|
+
npx ${CLI_NAME} init [--framework next|expo|react-native|vite]
|
|
9
|
+
npx ${CLI_NAME} add <component...> [--all] [--overwrite]
|
|
10
|
+
npx ${CLI_NAME} list
|
|
11
|
+
|
|
12
|
+
Options
|
|
13
|
+
--registry <url|path> Registry to read from (default: from advui.json, else ${DEFAULT_REGISTRY})
|
|
14
|
+
--cwd <path> Project directory (default: current directory)
|
|
15
|
+
--no-install Print the install command instead of running it
|
|
16
|
+
--overwrite Replace existing files
|
|
17
|
+
-h, --help Show this help`;
|
|
18
|
+
async function main(argv) {
|
|
19
|
+
const { values, positionals } = parseArgs({
|
|
20
|
+
args: argv,
|
|
21
|
+
allowPositionals: true,
|
|
22
|
+
options: {
|
|
23
|
+
registry: { type: 'string' },
|
|
24
|
+
cwd: { type: 'string' },
|
|
25
|
+
framework: { type: 'string' },
|
|
26
|
+
'no-install': { type: 'boolean', default: false },
|
|
27
|
+
overwrite: { type: 'boolean', default: false },
|
|
28
|
+
all: { type: 'boolean', default: false },
|
|
29
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
const [command, ...rest] = positionals;
|
|
33
|
+
if (values.help || !command) {
|
|
34
|
+
console.log(help);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const common = {
|
|
38
|
+
cwd: values.cwd ?? process.cwd(),
|
|
39
|
+
registry: values.registry,
|
|
40
|
+
install: !values['no-install'],
|
|
41
|
+
overwrite: values.overwrite ?? false,
|
|
42
|
+
log: (message) => console.log(message),
|
|
43
|
+
};
|
|
44
|
+
switch (command) {
|
|
45
|
+
case 'init':
|
|
46
|
+
return initCommand({ ...common, framework: values.framework });
|
|
47
|
+
case 'add':
|
|
48
|
+
return addCommand(rest, { ...common, all: values.all });
|
|
49
|
+
case 'list':
|
|
50
|
+
return listCommand(common);
|
|
51
|
+
default:
|
|
52
|
+
throw new Error(`Unknown command "${command}".\n\n${help}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
main(process.argv.slice(2)).catch((error) => {
|
|
56
|
+
console.error(error instanceof Error ? error.message : error);
|
|
57
|
+
process.exitCode = 1;
|
|
58
|
+
});
|
package/dist/project.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
export function readPackageJson(root) {
|
|
4
|
+
const file = join(root, 'package.json');
|
|
5
|
+
if (!existsSync(file))
|
|
6
|
+
return null;
|
|
7
|
+
return JSON.parse(readFileSync(file, 'utf8'));
|
|
8
|
+
}
|
|
9
|
+
export function detectFramework(deps) {
|
|
10
|
+
if (deps.next)
|
|
11
|
+
return 'next';
|
|
12
|
+
if (deps.expo)
|
|
13
|
+
return 'expo';
|
|
14
|
+
if (deps['react-native'])
|
|
15
|
+
return 'react-native';
|
|
16
|
+
if (deps.vite)
|
|
17
|
+
return 'vite';
|
|
18
|
+
return 'unknown';
|
|
19
|
+
}
|
|
20
|
+
export function detectPackageManager(root) {
|
|
21
|
+
if (existsSync(join(root, 'pnpm-lock.yaml')) || existsSync(join(root, 'pnpm-workspace.yaml')))
|
|
22
|
+
return 'pnpm';
|
|
23
|
+
if (existsSync(join(root, 'yarn.lock')))
|
|
24
|
+
return 'yarn';
|
|
25
|
+
if (existsSync(join(root, 'bun.lockb')) || existsSync(join(root, 'bun.lock')))
|
|
26
|
+
return 'bun';
|
|
27
|
+
return 'npm';
|
|
28
|
+
}
|
|
29
|
+
export function detectProject(root) {
|
|
30
|
+
const pkg = readPackageJson(root);
|
|
31
|
+
if (!pkg)
|
|
32
|
+
throw new Error(`No package.json found in ${root}. Run this inside your app.`);
|
|
33
|
+
const dependencies = {
|
|
34
|
+
...(pkg.dependencies ?? {}),
|
|
35
|
+
...(pkg.devDependencies ?? {}),
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
root,
|
|
39
|
+
framework: detectFramework(dependencies),
|
|
40
|
+
packageManager: detectPackageManager(root),
|
|
41
|
+
typescript: existsSync(join(root, 'tsconfig.json')),
|
|
42
|
+
srcDir: existsSync(join(root, 'src')),
|
|
43
|
+
dependencies,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export function installCommand(pm, packages, dev = false) {
|
|
47
|
+
const flag = dev ? (pm === 'npm' ? ' --save-dev' : ' -D') : '';
|
|
48
|
+
const verb = pm === 'npm' ? 'install' : 'add';
|
|
49
|
+
return `${pm} ${verb}${flag} ${packages.join(' ')}`;
|
|
50
|
+
}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { isAbsolute, join, resolve } from 'node:path';
|
|
3
|
+
const isUrl = (source) => /^https?:\/\//.test(source);
|
|
4
|
+
/** Loads `<name>.json` from a registry URL or local directory. */
|
|
5
|
+
export async function fetchRegistryJson(source, name, cwd) {
|
|
6
|
+
if (isUrl(source)) {
|
|
7
|
+
const url = `${source.replace(/\/$/, '')}/${name}.json`;
|
|
8
|
+
const response = await fetch(url);
|
|
9
|
+
if (!response.ok)
|
|
10
|
+
throw new Error(`Registry request failed: ${response.status} ${url}`);
|
|
11
|
+
return (await response.json());
|
|
12
|
+
}
|
|
13
|
+
const dir = isAbsolute(source) ? source : resolve(cwd, source);
|
|
14
|
+
const file = join(dir, `${name}.json`);
|
|
15
|
+
if (!existsSync(file))
|
|
16
|
+
throw new Error(`"${name}" not found in registry ${dir}`);
|
|
17
|
+
return JSON.parse(readFileSync(file, 'utf8'));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolves the requested items plus their registry dependencies (depth-first,
|
|
21
|
+
* dependencies before dependents, each item once).
|
|
22
|
+
*/
|
|
23
|
+
export async function resolveItems(names, load) {
|
|
24
|
+
const ordered = [];
|
|
25
|
+
const seen = new Set();
|
|
26
|
+
const visiting = new Set();
|
|
27
|
+
async function visit(name) {
|
|
28
|
+
if (seen.has(name))
|
|
29
|
+
return;
|
|
30
|
+
if (visiting.has(name))
|
|
31
|
+
throw new Error(`Circular registry dependency at "${name}"`);
|
|
32
|
+
visiting.add(name);
|
|
33
|
+
const item = await load(name);
|
|
34
|
+
for (const dependency of item.registryDependencies)
|
|
35
|
+
await visit(dependency);
|
|
36
|
+
visiting.delete(name);
|
|
37
|
+
seen.add(name);
|
|
38
|
+
ordered.push(item);
|
|
39
|
+
}
|
|
40
|
+
for (const name of names)
|
|
41
|
+
await visit(name);
|
|
42
|
+
return ordered;
|
|
43
|
+
}
|
|
44
|
+
export function collectDependencies(items) {
|
|
45
|
+
const all = new Set();
|
|
46
|
+
for (const item of items)
|
|
47
|
+
for (const dep of item.dependencies)
|
|
48
|
+
all.add(dep);
|
|
49
|
+
return [...all].sort();
|
|
50
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "advui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI to add Adv UI components to your project (shadcn-style source installation).",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/zinmin232/advui.git",
|
|
9
|
+
"directory": "packages/cli"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/zinmin232/advui/tree/main/packages/cli#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/zinmin232/advui/issues"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"bin": {
|
|
17
|
+
"advui": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=20"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^22.15.0",
|
|
31
|
+
"@advui/eslint-config": "0.1.0",
|
|
32
|
+
"@advui/tsconfig": "0.1.0",
|
|
33
|
+
"vitest": "^5.0.2"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc -p tsconfig.build.json",
|
|
37
|
+
"typecheck": "tsc --noEmit",
|
|
38
|
+
"lint": "eslint .",
|
|
39
|
+
"test": "vitest run",
|
|
40
|
+
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\""
|
|
41
|
+
}
|
|
42
|
+
}
|