@svgicons-com/cli 0.1.0-alpha.3 → 0.1.0-alpha.5
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/README.md +36 -2
- package/RELEASE_NOTES.md +25 -1
- package/package.json +2 -2
- package/src/api.js +19 -7
- package/src/cli.js +211 -5
- package/src/downloads.js +19 -0
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Public icon search works without changing the default endpoint. Pro workflows re
|
|
|
8
8
|
|
|
9
9
|
The scanner is read-only by default. It never edits project files unless a future command explicitly adds that behavior.
|
|
10
10
|
|
|
11
|
-
Current package version: `0.1.0-alpha.
|
|
11
|
+
Current package version: `0.1.0-alpha.5`.
|
|
12
12
|
|
|
13
13
|
## Requirements
|
|
14
14
|
|
|
@@ -60,6 +60,7 @@ svgicons icon show 33716
|
|
|
60
60
|
svgicons icon url 33716-arrow-circle-up-fill
|
|
61
61
|
svgicons icon raw 33716-arrow-circle-up-fill
|
|
62
62
|
svgicons icon download 33716-arrow-circle-up-fill --output ./icons
|
|
63
|
+
svgicons icon png 33716-arrow-circle-up-fill --size 512 --output ./icons
|
|
63
64
|
svgicons collection list
|
|
64
65
|
svgicons collection create --name "Dashboard icons" --description "Navigation and status icons"
|
|
65
66
|
svgicons collection show "Dashboard icons" --icons
|
|
@@ -69,7 +70,15 @@ svgicons collection add "Dashboard icons" 33716 240297
|
|
|
69
70
|
svgicons collection remove "Dashboard icons" 33716-arrow-circle-up-fill
|
|
70
71
|
svgicons collection delete "Dashboard icons" --yes
|
|
71
72
|
svgicons collection export "Dashboard icons" --formats react-ts,vue --color-policy currentColor --output ./exports
|
|
73
|
+
svgicons collection export "Dashboard icons" --formats svelte --output ./exports
|
|
74
|
+
svgicons collection export "Dashboard icons" --formats solid --output ./exports
|
|
75
|
+
svgicons collection export "Dashboard icons" --formats blade --output ./exports
|
|
76
|
+
svgicons collection export "Dashboard icons" --formats storybook --output ./exports
|
|
77
|
+
svgicons collection export "Dashboard icons" --formats npm-package --package-name svgicons-dashboard-icons --output ./exports
|
|
78
|
+
svgicons collection export "Dashboard icons" --formats png-pack --png-sizes 24,48,512 --output ./exports
|
|
79
|
+
svgicons collection export "Dashboard icons" --formats iconify-json --output ./exports
|
|
72
80
|
svgicons collection export "Dashboard icons" --formats react-ts --no-size-props --no-typescript --output ./exports
|
|
81
|
+
svgicons collection export "Dashboard icons" --formats react-ts,solid --default-size 20 --component-suffix Glyph --no-decorative --output ./exports
|
|
73
82
|
svgicons export status 55 --collection "Dashboard icons"
|
|
74
83
|
svgicons export download 55 --collection "Dashboard icons" --output ./exports
|
|
75
84
|
svgicons init --collection "Dashboard icons" --output ./src/icons
|
|
@@ -116,6 +125,16 @@ The icon reference must include both the numeric ID and the icon name, such as `
|
|
|
116
125
|
|
|
117
126
|
This command uses the MCP `get_icon` tool with raw SVG output, so the token needs `mcp:use` and `icons:read`. Existing files are not overwritten unless you add `--force`.
|
|
118
127
|
|
|
128
|
+
Export a Pro PNG asset from a single icon:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
svgicons icon png 33716-arrow-circle-up-fill --size 512 --output ./icons
|
|
132
|
+
svgicons icon png 33716-arrow-circle-up-fill --sizes 128,256,512 --density 1,2 --zip --output ./icons
|
|
133
|
+
svgicons icon png 33716-arrow-circle-up-fill --size 512 --color black --background solid --background-color "#ffffff"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Single-icon PNG export uses the Pro REST API, not the public anonymous search API. The token needs `icons:read` and `exports:create`. The icon reference must include both ID and name, and the server verifies that the name matches before rendering.
|
|
137
|
+
|
|
119
138
|
Read-only icon commands accept a numeric ID, an `id-name` reference, or a full svgicons.com icon URL:
|
|
120
139
|
|
|
121
140
|
```bash
|
|
@@ -174,13 +193,28 @@ The command polls every 2 seconds for up to 180 seconds by default. Use `--timeo
|
|
|
174
193
|
Supported export flags:
|
|
175
194
|
|
|
176
195
|
```bash
|
|
177
|
-
--formats react-ts,vue
|
|
196
|
+
--formats react-ts,vue,svelte,solid,blade,storybook,npm-package,png-pack,iconify-json
|
|
178
197
|
--color-policy currentColor|preserve|strip
|
|
179
198
|
--naming-policy kebab|pascal|camel
|
|
180
199
|
--size-props / --no-size-props
|
|
181
200
|
--typescript / --no-typescript
|
|
201
|
+
--default-size 24
|
|
202
|
+
--title-prop / --no-title-prop
|
|
203
|
+
--decorative / --no-decorative
|
|
204
|
+
--component-suffix Icon
|
|
205
|
+
--package-name svgicons-dashboard-icons
|
|
206
|
+
--package-version 0.1.0
|
|
207
|
+
--png-sizes 24,48,512
|
|
208
|
+
--png-densities 1,2
|
|
209
|
+
--png-background transparent|solid
|
|
210
|
+
--png-background-color "#ffffff"
|
|
211
|
+
--png-color preserve|black|white|custom
|
|
212
|
+
--png-icon-color "#2563eb"
|
|
213
|
+
--png-padding 48
|
|
182
214
|
```
|
|
183
215
|
|
|
216
|
+
Use `--formats png` as a shorthand for `--formats png-pack`. PNG pack exports are generated by the server queue worker and downloaded as part of the collection ZIP. Use `--formats svelte` to include Svelte components, `--formats solid` to include Solid components, `--formats blade` to include Laravel Blade components, `--formats storybook` to include a React Storybook gallery, `--formats npm-package` to include a React TypeScript package scaffold, or `--formats iconify-json` to include an Iconify-compatible `iconify.json` file in the collection ZIP.
|
|
217
|
+
|
|
184
218
|
Collection commands accept a numeric ID, exact slug, or exact case-insensitive collection name. The legacy `kit` alias remains available for old scripts.
|
|
185
219
|
|
|
186
220
|
Lifecycle commands are available for collection maintenance:
|
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,4 +1,27 @@
|
|
|
1
|
-
# Svg/icons CLI 0.1.0-alpha.
|
|
1
|
+
# Svg/icons CLI 0.1.0-alpha.5
|
|
2
|
+
|
|
3
|
+
This alpha refresh keeps the npm alpha channel aligned with the current Svg/icons Pro export workflow.
|
|
4
|
+
|
|
5
|
+
## New in 0.1.0-alpha.5
|
|
6
|
+
|
|
7
|
+
- Version bump for npm alpha publication after `0.1.0-alpha.4`.
|
|
8
|
+
- No runtime command changes from `0.1.0-alpha.4`.
|
|
9
|
+
- Keeps the package README and release notes aligned with the current CLI export surface.
|
|
10
|
+
|
|
11
|
+
## 0.1.0-alpha.4
|
|
12
|
+
|
|
13
|
+
This alpha brought the CLI up to date with the current Svg/icons Pro export workflow.
|
|
14
|
+
|
|
15
|
+
- Added single-icon PNG export with `svgicons icon png`, including PNG and ZIP variant downloads.
|
|
16
|
+
- Added collection PNG pack export with size, density, background, color, padding, and fit options.
|
|
17
|
+
- Added collection export format support for `svelte`, `solid`, `blade`, `storybook`, `npm-package`, and `iconify-json`.
|
|
18
|
+
- Added `png` as a shorthand for the `png-pack` collection export format.
|
|
19
|
+
- Added safe framework export options: `--default-size`, `--component-suffix`, `--title-prop`, `--no-title-prop`, `--decorative`, and `--no-decorative`.
|
|
20
|
+
- Added npm package export metadata options: `--package-name` and `--package-version`.
|
|
21
|
+
- Added `svgicons export download <export-id> --collection <collection>` for downloading queued collection export ZIPs.
|
|
22
|
+
- Updated CLI docs and tests for the newer Pro API export formats.
|
|
23
|
+
|
|
24
|
+
## 0.1.0-alpha.3
|
|
2
25
|
|
|
3
26
|
This alpha refresh improves token setup safety. `login` now rejects obviously truncated numeric tokens, which commonly happens when a shell command is run without quoting a Sanctum-style token containing `|`.
|
|
4
27
|
|
|
@@ -44,6 +67,7 @@ Before publishing, run:
|
|
|
44
67
|
|
|
45
68
|
```bash
|
|
46
69
|
npm --prefix cli test
|
|
70
|
+
cd cli
|
|
47
71
|
npm pack --dry-run
|
|
48
72
|
```
|
|
49
73
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@svgicons-com/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.5",
|
|
4
4
|
"description": "Svg/icons CLI alpha for icon search, Pro collections, exports, project scanning, and license workflows.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"RELEASE_NOTES.md"
|
|
14
14
|
],
|
|
15
15
|
"scripts": {
|
|
16
|
-
"test": "node --test
|
|
16
|
+
"test": "node --test"
|
|
17
17
|
},
|
|
18
18
|
"engines": {
|
|
19
19
|
"node": ">=18.18"
|
package/src/api.js
CHANGED
|
@@ -79,14 +79,26 @@ export async function proApiDownload(pathOrUrl, options = {}) {
|
|
|
79
79
|
let response;
|
|
80
80
|
|
|
81
81
|
try {
|
|
82
|
-
|
|
82
|
+
const headers = {
|
|
83
|
+
Accept: 'image/png, application/zip, application/octet-stream',
|
|
84
|
+
Authorization: `Bearer ${token}`,
|
|
85
|
+
'User-Agent': 'svgicons-cli/0.1.0-alpha',
|
|
86
|
+
...options.headers,
|
|
87
|
+
};
|
|
88
|
+
const init = {
|
|
83
89
|
method: options.method || 'GET',
|
|
84
|
-
headers
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
headers,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
if (options.body !== undefined) {
|
|
94
|
+
headers['Content-Type'] = headers['Content-Type'] || 'application/json';
|
|
95
|
+
init.body = typeof options.body === 'string' || options.body instanceof Buffer
|
|
96
|
+
? options.body
|
|
97
|
+
: JSON.stringify(options.body);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
response = await fetch(url, {
|
|
101
|
+
...init,
|
|
90
102
|
});
|
|
91
103
|
} catch (error) {
|
|
92
104
|
throw networkError(error, url);
|
package/src/cli.js
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
parseIconReference,
|
|
23
23
|
resolveArchiveDownloadPath,
|
|
24
24
|
resolveIconDownloadPath,
|
|
25
|
+
resolvePngDownloadPath,
|
|
25
26
|
sanitizeFileSegment,
|
|
26
27
|
writeBinaryFile,
|
|
27
28
|
writeIconSvg,
|
|
@@ -56,10 +57,29 @@ const KNOWN_SCOPES = [
|
|
|
56
57
|
'exports:create',
|
|
57
58
|
'mcp:use',
|
|
58
59
|
];
|
|
59
|
-
const EXPORT_FORMATS = [
|
|
60
|
+
const EXPORT_FORMATS = [
|
|
61
|
+
'svg-folder',
|
|
62
|
+
'svg-sprite',
|
|
63
|
+
'json-manifest',
|
|
64
|
+
'license-manifest',
|
|
65
|
+
'react-ts',
|
|
66
|
+
'vue',
|
|
67
|
+
'svelte',
|
|
68
|
+
'solid',
|
|
69
|
+
'blade',
|
|
70
|
+
'storybook',
|
|
71
|
+
'npm-package',
|
|
72
|
+
'png-pack',
|
|
73
|
+
'iconify-json',
|
|
74
|
+
];
|
|
60
75
|
const FRAMEWORKS = ['svg', 'react-ts', 'vue', 'sprite'];
|
|
61
76
|
const COLOR_POLICIES = ['currentColor', 'preserve', 'strip'];
|
|
62
77
|
const NAMING_POLICIES = ['kebab', 'pascal', 'camel'];
|
|
78
|
+
const PNG_SIZES = [16, 24, 32, 48, 96, 128, 256, 512, 1024];
|
|
79
|
+
const PNG_DENSITIES = [1, 2, 3, 4];
|
|
80
|
+
const PNG_BACKGROUNDS = ['transparent', 'solid'];
|
|
81
|
+
const PNG_COLORS = ['preserve', 'black', 'white', 'custom'];
|
|
82
|
+
const PNG_FITS = ['contain'];
|
|
63
83
|
|
|
64
84
|
export async function run(argv) {
|
|
65
85
|
const { args, options: globalOptions } = extractGlobalOptions(argv);
|
|
@@ -633,7 +653,12 @@ async function icon(args) {
|
|
|
633
653
|
return;
|
|
634
654
|
}
|
|
635
655
|
|
|
636
|
-
|
|
656
|
+
if (subcommand === 'png') {
|
|
657
|
+
await iconPng(rest);
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
throw new Error('Unknown icon command. Use: show, raw, url, open, download, png.');
|
|
637
662
|
}
|
|
638
663
|
|
|
639
664
|
async function iconShow(args) {
|
|
@@ -715,6 +740,40 @@ async function iconDownload(args) {
|
|
|
715
740
|
console.log(` ${outputPath}`);
|
|
716
741
|
}
|
|
717
742
|
|
|
743
|
+
async function iconPng(args) {
|
|
744
|
+
const options = parseOptions(args);
|
|
745
|
+
const [iconReference] = options._;
|
|
746
|
+
const reference = parseIconReference(iconReference);
|
|
747
|
+
const payload = buildIconPngPayload(reference, options);
|
|
748
|
+
const download = await proApiDownload(`/api/pro/icons/${encodeURIComponent(reference.id)}/png-export`, {
|
|
749
|
+
method: 'POST',
|
|
750
|
+
body: payload,
|
|
751
|
+
headers: {
|
|
752
|
+
'Content-Type': 'application/json',
|
|
753
|
+
},
|
|
754
|
+
});
|
|
755
|
+
const outputPath = resolvePngDownloadPath(options.output || options.o, download.filename, process.cwd());
|
|
756
|
+
|
|
757
|
+
await writeBinaryFile(outputPath, download.bytes, booleanOption(options.force, false));
|
|
758
|
+
|
|
759
|
+
if (options.json) {
|
|
760
|
+
printJson({
|
|
761
|
+
icon: {
|
|
762
|
+
id: reference.id,
|
|
763
|
+
name: reference.slug,
|
|
764
|
+
},
|
|
765
|
+
outputPath,
|
|
766
|
+
contentType: download.contentType,
|
|
767
|
+
filename: download.filename,
|
|
768
|
+
options: payload,
|
|
769
|
+
});
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
console.log(`Downloaded PNG export`);
|
|
774
|
+
console.log(` ${outputPath}`);
|
|
775
|
+
}
|
|
776
|
+
|
|
718
777
|
async function collection(args) {
|
|
719
778
|
const [subcommand, ...rest] = args;
|
|
720
779
|
|
|
@@ -1173,7 +1232,7 @@ async function buildProject(args) {
|
|
|
1173
1232
|
const format = options.format || manifest.format || 'svg';
|
|
1174
1233
|
|
|
1175
1234
|
if (format !== 'svg') {
|
|
1176
|
-
throw usageError('Local build currently supports format svg. Use collection export for React TypeScript or
|
|
1235
|
+
throw usageError('Local build currently supports format svg. Use collection export for React TypeScript, Vue, Svelte, or Solid component ZIPs.');
|
|
1177
1236
|
}
|
|
1178
1237
|
|
|
1179
1238
|
const outputDir = resolve(String(options.output || options.o || manifest.output));
|
|
@@ -1830,17 +1889,163 @@ function extensionSet(value) {
|
|
|
1830
1889
|
}
|
|
1831
1890
|
|
|
1832
1891
|
function buildExportOptions(options) {
|
|
1892
|
+
const formats = exportFormatsOption(options.formats);
|
|
1893
|
+
const png = buildCollectionPngOptions(options);
|
|
1894
|
+
const includesPng = formats?.includes('png-pack') || Object.keys(png).length > 0;
|
|
1895
|
+
const normalizedFormats = includesPng && formats === undefined
|
|
1896
|
+
? ['png-pack']
|
|
1897
|
+
: formats;
|
|
1898
|
+
|
|
1833
1899
|
return {
|
|
1834
|
-
formats:
|
|
1900
|
+
formats: normalizedFormats,
|
|
1835
1901
|
options: {
|
|
1836
1902
|
colorPolicy: enumOption(options['color-policy'], 'color policy', COLOR_POLICIES),
|
|
1837
1903
|
namingPolicy: enumOption(options['naming-policy'], 'naming policy', NAMING_POLICIES),
|
|
1838
1904
|
sizeProps: booleanFlagPair(options, 'size-props', 'no-size-props'),
|
|
1839
1905
|
typescript: booleanFlagPair(options, 'typescript', 'no-typescript'),
|
|
1906
|
+
defaultSize: boundedIntegerOption(options['default-size'], 'default component size', 1, 1024),
|
|
1907
|
+
titleProp: booleanFlagPair(options, 'title-prop', 'no-title-prop'),
|
|
1908
|
+
decorative: booleanFlagPair(options, 'decorative', 'no-decorative'),
|
|
1909
|
+
componentSuffix: identifierOption(options['component-suffix'], 'component suffix'),
|
|
1910
|
+
packageName: packageNameOption(options['package-name']),
|
|
1911
|
+
packageVersion: packageVersionOption(options['package-version']),
|
|
1912
|
+
png: includesPng ? png : undefined,
|
|
1840
1913
|
},
|
|
1841
1914
|
};
|
|
1842
1915
|
}
|
|
1843
1916
|
|
|
1917
|
+
function buildIconPngPayload(reference, options) {
|
|
1918
|
+
return {
|
|
1919
|
+
iconName: reference.slug,
|
|
1920
|
+
sizes: integerCsvOption(options.sizes ?? options.size, 'PNG size', PNG_SIZES, [512]),
|
|
1921
|
+
densities: integerCsvOption(options.densities ?? options.density, 'PNG density', PNG_DENSITIES, [1]),
|
|
1922
|
+
backgroundType: enumOption(options.background, 'PNG background', PNG_BACKGROUNDS),
|
|
1923
|
+
backgroundColor: options['background-color'],
|
|
1924
|
+
iconColorMode: enumOption(options.color, 'PNG icon color mode', PNG_COLORS),
|
|
1925
|
+
iconColor: options['icon-color'],
|
|
1926
|
+
padding: integerOption(options.padding, 'PNG padding'),
|
|
1927
|
+
fit: enumOption(options.fit, 'PNG fit mode', PNG_FITS),
|
|
1928
|
+
filename: options.filename,
|
|
1929
|
+
zip: booleanOption(options.zip, undefined),
|
|
1930
|
+
};
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
function buildCollectionPngOptions(options) {
|
|
1934
|
+
return stripUndefined({
|
|
1935
|
+
sizes: integerCsvOption(options['png-sizes'] ?? options['png-size'], 'PNG size', PNG_SIZES, undefined),
|
|
1936
|
+
densities: integerCsvOption(options['png-densities'] ?? options['png-density'], 'PNG density', [1, 2, 3], undefined),
|
|
1937
|
+
backgroundType: enumOption(options['png-background'], 'PNG background', PNG_BACKGROUNDS),
|
|
1938
|
+
backgroundColor: options['png-background-color'],
|
|
1939
|
+
iconColorMode: enumOption(options['png-color'], 'PNG icon color mode', PNG_COLORS),
|
|
1940
|
+
iconColor: options['png-icon-color'],
|
|
1941
|
+
padding: integerOption(options['png-padding'], 'PNG padding'),
|
|
1942
|
+
fit: enumOption(options['png-fit'], 'PNG fit mode', PNG_FITS),
|
|
1943
|
+
});
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
function exportFormatsOption(value) {
|
|
1947
|
+
const values = csvOption(value);
|
|
1948
|
+
|
|
1949
|
+
if (!values) {
|
|
1950
|
+
return undefined;
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
const normalized = values.map((item) => item === 'png' ? 'png-pack' : item);
|
|
1954
|
+
const invalid = normalized.filter((item) => !EXPORT_FORMATS.includes(item));
|
|
1955
|
+
if (invalid.length > 0) {
|
|
1956
|
+
throw usageError(`Invalid export format: ${invalid.join(', ')}. Allowed values: ${EXPORT_FORMATS.join(', ')}, png`);
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
return [...new Set(normalized)];
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
function integerCsvOption(value, label, allowed, fallback) {
|
|
1963
|
+
const values = csvOption(value);
|
|
1964
|
+
|
|
1965
|
+
if (!values) {
|
|
1966
|
+
return fallback;
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
const parsed = values.map((item) => Number(item));
|
|
1970
|
+
const invalid = parsed.filter((item) => !Number.isInteger(item) || !allowed.includes(item));
|
|
1971
|
+
|
|
1972
|
+
if (invalid.length > 0) {
|
|
1973
|
+
throw usageError(`Invalid ${label}: ${invalid.join(', ')}. Allowed values: ${allowed.join(', ')}`);
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
return [...new Set(parsed)];
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
function integerOption(value, label) {
|
|
1980
|
+
if (value === undefined || value === true || value === '') {
|
|
1981
|
+
return undefined;
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
const parsed = Number(value);
|
|
1985
|
+
if (!Number.isInteger(parsed)) {
|
|
1986
|
+
throw usageError(`Invalid ${label}: ${value}. Expected an integer.`);
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
return parsed;
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
function boundedIntegerOption(value, label, min, max) {
|
|
1993
|
+
const parsed = integerOption(value, label);
|
|
1994
|
+
|
|
1995
|
+
if (parsed === undefined) {
|
|
1996
|
+
return undefined;
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
if (parsed < min || parsed > max) {
|
|
2000
|
+
throw usageError(`Invalid ${label}: ${value}. Allowed range: ${min}-${max}.`);
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
return parsed;
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
function identifierOption(value, label) {
|
|
2007
|
+
if (value === undefined || value === true || value === '') {
|
|
2008
|
+
return undefined;
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
const parsed = String(value);
|
|
2012
|
+
if (!/^[A-Za-z][A-Za-z0-9]{0,31}$/.test(parsed)) {
|
|
2013
|
+
throw usageError(`Invalid ${label}: ${value}. Use 1-32 letters or numbers, starting with a letter.`);
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
return parsed;
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
function packageNameOption(value) {
|
|
2020
|
+
if (value === undefined || value === true || value === '') {
|
|
2021
|
+
return undefined;
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
const parsed = String(value);
|
|
2025
|
+
if (parsed.length > 214 || parsed.toLowerCase() !== parsed || !/^(?:@[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*|[a-z0-9][a-z0-9._-]*)$/.test(parsed)) {
|
|
2026
|
+
throw usageError(`Invalid npm package name: ${value}. Use a lowercase npm package name such as svgicons-dashboard or @svgicons-com/dashboard.`);
|
|
2027
|
+
}
|
|
2028
|
+
|
|
2029
|
+
return parsed;
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
function packageVersionOption(value) {
|
|
2033
|
+
if (value === undefined || value === true || value === '') {
|
|
2034
|
+
return undefined;
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
const parsed = String(value);
|
|
2038
|
+
if (parsed.length > 64 || !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(parsed)) {
|
|
2039
|
+
throw usageError(`Invalid npm package version: ${value}. Use a semver-like version such as 1.0.0 or 1.0.0-beta.1.`);
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
return parsed;
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
function stripUndefined(value) {
|
|
2046
|
+
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
|
|
2047
|
+
}
|
|
2048
|
+
|
|
1844
2049
|
function enumOption(value, label, allowed) {
|
|
1845
2050
|
if (value === undefined || value === true || value === '') {
|
|
1846
2051
|
return undefined;
|
|
@@ -1894,6 +2099,7 @@ Usage:
|
|
|
1894
2099
|
svgicons icon url <icon-ref>
|
|
1895
2100
|
svgicons icon open <icon-ref>
|
|
1896
2101
|
svgicons icon download <icon-id-name> [--output ./icons] [--force]
|
|
2102
|
+
svgicons icon png <icon-id-name> [--size 512] [--density 1,2] [--output ./icons] [--force]
|
|
1897
2103
|
svgicons collection list [--json]
|
|
1898
2104
|
svgicons collection create --name "Dashboard icons"
|
|
1899
2105
|
svgicons collection show <collection-id-or-name> [--icons] [--json]
|
|
@@ -1902,7 +2108,7 @@ Usage:
|
|
|
1902
2108
|
svgicons collection add <collection-id-or-name> <icon-id...>
|
|
1903
2109
|
svgicons collection remove <collection-id-or-name> <icon-id...>
|
|
1904
2110
|
svgicons collection delete <collection-id-or-name> [--yes]
|
|
1905
|
-
svgicons collection export <collection-id-or-name> [--formats react-ts,vue] [--no-size-props] [--no-typescript] [--output ./exports]
|
|
2111
|
+
svgicons collection export <collection-id-or-name> [--formats react-ts,vue,svelte,solid,blade,storybook,npm-package,png-pack,iconify-json] [--default-size 24] [--component-suffix Icon] [--package-name svgicons-dashboard] [--package-version 0.1.0] [--title-prop|--no-title-prop] [--decorative|--no-decorative] [--no-size-props] [--no-typescript] [--output ./exports]
|
|
1906
2112
|
svgicons export status <export-id> --collection <collection-id-or-name>
|
|
1907
2113
|
svgicons export download <export-id> --collection <collection-id-or-name> [--output ./exports]
|
|
1908
2114
|
svgicons init [--collection <collection-id-or-name>] [--output svgicons-icons]
|
package/src/downloads.js
CHANGED
|
@@ -95,6 +95,25 @@ export function resolveArchiveDownloadPath(output, filename, cwd = process.cwd()
|
|
|
95
95
|
return join(target, safeFilename);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
export function resolvePngDownloadPath(output, filename, cwd = process.cwd()) {
|
|
99
|
+
const safeFilename = sanitizeFileName(filename || 'svgicons-icon.png', 'png');
|
|
100
|
+
|
|
101
|
+
if (!output || output === true) {
|
|
102
|
+
return resolve(cwd, safeFilename);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const target = isAbsolute(String(output))
|
|
106
|
+
? String(output)
|
|
107
|
+
: resolve(cwd, String(output));
|
|
108
|
+
|
|
109
|
+
const extension = extname(target).toLowerCase();
|
|
110
|
+
if (extension === '.png' || extension === '.zip') {
|
|
111
|
+
return target;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return join(target, safeFilename);
|
|
115
|
+
}
|
|
116
|
+
|
|
98
117
|
export async function writeIconSvg(path, svg, force = false) {
|
|
99
118
|
if (!svg || typeof svg !== 'string') {
|
|
100
119
|
throw new Error('The icon response did not include SVG markup.');
|