@shaquillehinds/react-native-svg-icons 0.1.0 → 0.1.2

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.
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ const PACKAGE_NAME = '@shaquillehinds/react-native-svg-icons';
8
+
9
+ const CANDIDATE_TYPE_PATHS = [
10
+ path.join(__dirname, '..', 'src', 'svgs', 'types.ts'),
11
+ path.join(__dirname, '..', 'lib', 'typescript', 'svgs', 'types.d.ts'),
12
+ path.join(__dirname, '..', 'lib', 'commonjs', 'svgs', 'types.d.ts'),
13
+ ];
14
+
15
+ const HELP = `
16
+ rnsi-icons — look up real icon names from ${PACKAGE_NAME}
17
+
18
+ Names in this set are irregular and some are misspelled. Search here rather
19
+ than guessing.
20
+
21
+ Usage
22
+ npx rnsi-icons <query> [--type filled|outline] [--exact] [--limit N]
23
+ npx rnsi-icons --list [--type filled|outline]
24
+
25
+ Options
26
+ --type <t> restrict to one variant (default: both)
27
+ --exact exact, case-sensitive match only
28
+ --limit N cap results (default 40, 0 for no cap)
29
+ --json machine-readable output
30
+ --shared with --list, only names present in both variants
31
+ --diff show names that exist in one variant but not the other
32
+ --help show this message
33
+
34
+ Examples
35
+ npx rnsi-icons search
36
+ npx rnsi-icons arrow --type outline --limit 100
37
+ npx rnsi-icons Trash --exact
38
+ npx rnsi-icons --diff
39
+ npx rnsi-icons --list --shared > icons.txt
40
+ `;
41
+
42
+ function loadSource() {
43
+ for (const p of CANDIDATE_TYPE_PATHS) {
44
+ if (fs.existsSync(p)) return fs.readFileSync(p, 'utf8');
45
+ }
46
+ return null;
47
+ }
48
+
49
+ function parseUnion(source, typeName) {
50
+ const start = source.indexOf('export type ' + typeName);
51
+ if (start === -1) return [];
52
+ const end = source.indexOf(';', start);
53
+ const block = source.slice(start, end === -1 ? undefined : end);
54
+ const names = [];
55
+ const re = /'([^']+)'/g;
56
+ let m;
57
+ while ((m = re.exec(block)) !== null) names.push(m[1]);
58
+ return names;
59
+ }
60
+
61
+ function flag(argv, name) {
62
+ return argv.includes('--' + name);
63
+ }
64
+
65
+ function value(argv, name, fallback) {
66
+ const i = argv.indexOf('--' + name);
67
+ if (i === -1 || i === argv.length - 1) return fallback;
68
+ return argv[i + 1];
69
+ }
70
+
71
+ function main() {
72
+ const argv = process.argv.slice(2);
73
+
74
+ if (flag(argv, 'help') || argv.includes('-h') || argv.length === 0) {
75
+ process.stdout.write(HELP);
76
+ return;
77
+ }
78
+
79
+ const source = loadSource();
80
+ if (!source) {
81
+ console.error(
82
+ `rnsi-icons: could not locate the icon type definitions.\n` +
83
+ `Is ${PACKAGE_NAME} installed?`
84
+ );
85
+ process.exitCode = 1;
86
+ return;
87
+ }
88
+
89
+ const filled = parseUnion(source, 'FilledIconName');
90
+ const outline = parseUnion(source, 'OutlineIconName');
91
+
92
+ if (!filled.length && !outline.length) {
93
+ console.error(
94
+ $lf(93),
95
+ 'rnsi-icons: parsed zero icon names — the types file may have changed shape.'
96
+ );
97
+ process.exitCode = 1;
98
+ return;
99
+ }
100
+
101
+ const asJson = flag(argv, 'json');
102
+ const exact = flag(argv, 'exact');
103
+ const type = value(argv, 'type', null);
104
+ const limitRaw = value(argv, 'limit', '40');
105
+ const limit = Number(limitRaw) === 0 ? Infinity : Number(limitRaw) || 40;
106
+
107
+ if (type && type !== 'filled' && type !== 'outline') {
108
+ console.error(
109
+ $lf(105),
110
+ `rnsi-icons: --type must be "filled" or "outline", got "${type}".`
111
+ );
112
+ process.exitCode = 1;
113
+ return;
114
+ }
115
+
116
+ const filledSet = new Set(filled);
117
+ const outlineSet = new Set(outline);
118
+
119
+ if (flag(argv, 'diff')) {
120
+ const onlyFilled = filled.filter((n) => !outlineSet.has(n));
121
+ const onlyOutline = outline.filter((n) => !filledSet.has(n));
122
+ if (asJson) {
123
+ process.stdout.write(
124
+ JSON.stringify({ onlyFilled, onlyOutline }, null, 2) + '\n'
125
+ );
126
+ return;
127
+ }
128
+ console.log(
129
+ $lf(120),
130
+ `filled: ${filled.length} outline: ${outline.length}`
131
+ );
132
+ console.log(
133
+ $lf(121),
134
+ `shared: ${filled.filter((n) => outlineSet.has(n)).length}\n`
135
+ );
136
+ console.log(
137
+ $lf(122),
138
+ 'filled only: ' + (onlyFilled.join(', ') || '(none)')
139
+ );
140
+ console.log(
141
+ $lf(123),
142
+ 'outline only: ' + (onlyOutline.join(', ') || '(none)')
143
+ );
144
+ return;
145
+ }
146
+
147
+ let pool;
148
+ if (type === 'filled') pool = filled.map((n) => [n, 'filled']);
149
+ else if (type === 'outline') pool = outline.map((n) => [n, 'outline']);
150
+ else {
151
+ const all = new Set([...filled, ...outline]);
152
+ pool = [...all].sort().map((n) => {
153
+ const inF = filledSet.has(n);
154
+ const inO = outlineSet.has(n);
155
+ return [n, inF && inO ? 'both' : inF ? 'filled' : 'outline'];
156
+ });
157
+ }
158
+
159
+ if (flag(argv, 'list')) {
160
+ let rows = pool;
161
+ if (flag(argv, 'shared')) rows = rows.filter(([, v]) => v === 'both');
162
+ if (asJson) {
163
+ process.stdout.write(
164
+ JSON.stringify(
165
+ rows.map(([n, v]) => ({ name: n, variant: v })),
166
+ null,
167
+ 2
168
+ ) + '\n'
169
+ );
170
+ return;
171
+ }
172
+ rows.forEach(([n]) => console.log($lf(146), n));
173
+ return;
174
+ }
175
+
176
+ const VALUE_FLAGS = new Set(['--type', '--limit']);
177
+ let query = null;
178
+ for (let i = 0; i < argv.length; i++) {
179
+ const arg = argv[i];
180
+ if (VALUE_FLAGS.has(arg)) {
181
+ i++; // skip this flag's value
182
+ continue;
183
+ }
184
+ if (arg.startsWith('-')) continue;
185
+ query = arg;
186
+ break;
187
+ }
188
+
189
+ if (!query) {
190
+ console.error(
191
+ $lf(164),
192
+ 'rnsi-icons: no query given. Run with --help for usage.'
193
+ );
194
+ process.exitCode = 1;
195
+ return;
196
+ }
197
+
198
+ const q = query.toLowerCase();
199
+ const matches = pool.filter(([n]) =>
200
+ exact ? n === query : n.toLowerCase().includes(q)
201
+ );
202
+
203
+ // Prefix matches first, then shortest — closest names surface at the top.
204
+ matches.sort((a, b) => {
205
+ const ap = a[0].toLowerCase().startsWith(q) ? 0 : 1;
206
+ const bp = b[0].toLowerCase().startsWith(q) ? 0 : 1;
207
+ if (ap !== bp) return ap - bp;
208
+ if (a[0].length !== b[0].length) return a[0].length - b[0].length;
209
+ return a[0].localeCompare(b[0]);
210
+ });
211
+
212
+ if (asJson) {
213
+ process.stdout.write(
214
+ JSON.stringify(
215
+ matches.map(([n, v]) => ({ name: n, variant: v })),
216
+ null,
217
+ 2
218
+ ) + '\n'
219
+ );
220
+ return;
221
+ }
222
+
223
+ if (!matches.length) {
224
+ console.log($lf(191), `No icon matches "${query}".`);
225
+ console.log(
226
+ $lf(192),
227
+ 'Try a shorter fragment, or run: npx rnsi-icons --list'
228
+ );
229
+ process.exitCode = 1;
230
+ return;
231
+ }
232
+
233
+ const shown = matches.slice(0, limit);
234
+ const width = Math.max(...shown.map(([n]) => n.length));
235
+ shown.forEach(([n, v]) => console.log($lf(199), n.padEnd(width + 2) + v));
236
+
237
+ if (matches.length > shown.length) {
238
+ console.log(
239
+ `\n… ${matches.length - shown.length} more. Use --limit 0 to show all.`
240
+ );
241
+ }
242
+ }
243
+
244
+ main();
245
+ function $lf(n) {
246
+ return '$lf|bin/find-icon.js:' + n + ' >';
247
+ // Automatically injected by Log Location Injector vscode extension
248
+ }
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ const PACKAGE_NAME = '@shaquillehinds/react-native-svg-icons';
8
+ const SLUG = 'react-native-svg-icons';
9
+ const SOURCE = path.join(__dirname, '..', 'rules', 'AGENT_RULES.md');
10
+
11
+ const TARGETS = {
12
+ agents: 'AGENTS.md',
13
+ cursor: path.join('.cursor', 'rules', SLUG + '.mdc'),
14
+ claude: path.join('.claude', 'rules', SLUG + '.md'),
15
+ codex: path.join('.codex', 'rules', SLUG + '.md'),
16
+ copilot: path.join('.github', 'instructions', SLUG + '.instructions.md'),
17
+ windsurf: path.join('.windsurf', 'rules', SLUG + '.md'),
18
+ };
19
+
20
+ const HELP = `
21
+ rnsi-rules — install the ${PACKAGE_NAME} agent rules
22
+
23
+ Usage
24
+ npx rnsi-rules [target|path] [--force] [--print]
25
+
26
+ Targets
27
+ (none) ./AGENTS.md
28
+ agents ./AGENTS.md
29
+ cursor ./.cursor/rules/${SLUG}.mdc (alwaysApply)
30
+ claude ./.claude/rules/${SLUG}.md
31
+ codex ./.codex/rules/${SLUG}.md
32
+ copilot ./.github/instructions/${SLUG}.instructions.md
33
+ windsurf ./.windsurf/rules/${SLUG}.md
34
+ <path> any path ending in .md or .mdc
35
+
36
+ Options
37
+ --force overwrite an existing file
38
+ --print write nothing, print the rules to stdout
39
+ --help show this message
40
+
41
+ Examples
42
+ npx rnsi-rules
43
+ npx rnsi-rules cursor
44
+ npx rnsi-rules docs/ai/svg-icons.md --force
45
+ `;
46
+
47
+ function frontmatterFor(target) {
48
+ if (target === 'cursor') {
49
+ return [
50
+ '---',
51
+ `description: How to use ${PACKAGE_NAME} correctly`,
52
+ 'globs:',
53
+ 'alwaysApply: true',
54
+ '---',
55
+ '',
56
+ '',
57
+ ].join('\n');
58
+ }
59
+ if (target === 'copilot') {
60
+ return ['---', "applyTo: '**/*.tsx,**/*.ts'", '---', '', ''].join('\n');
61
+ }
62
+ if (target === 'windsurf') {
63
+ return ['---', 'trigger: always_on', '---', '', ''].join('\n');
64
+ }
65
+ return '';
66
+ }
67
+
68
+ function resolveTarget(arg) {
69
+ if (!arg) return { target: 'agents', relPath: TARGETS.agents };
70
+ if (Object.prototype.hasOwnProperty.call(TARGETS, arg)) {
71
+ return { target: arg, relPath: TARGETS[arg] };
72
+ }
73
+ if (/\.mdx?$|\.mdc$/.test(arg)) {
74
+ return { target: 'custom', relPath: arg };
75
+ }
76
+ return null;
77
+ }
78
+
79
+ function main() {
80
+ const argv = process.argv.slice(2);
81
+ const force = argv.includes('--force') || argv.includes('-f');
82
+ const print = argv.includes('--print');
83
+ const help = argv.includes('--help') || argv.includes('-h');
84
+ const positional = argv.filter((a) => !a.startsWith('-'))[0];
85
+
86
+ if (help) {
87
+ process.stdout.write(HELP);
88
+ return;
89
+ }
90
+
91
+ let rules;
92
+ try {
93
+ rules = fs.readFileSync(SOURCE, 'utf8');
94
+ } catch (err) {
95
+ console.error(
96
+ `rnsi-rules: could not read the rules file at ${SOURCE}\n` +
97
+ `Is ${PACKAGE_NAME} installed?`
98
+ );
99
+ process.exitCode = 1;
100
+ return;
101
+ }
102
+
103
+ if (print) {
104
+ process.stdout.write(rules);
105
+ return;
106
+ }
107
+
108
+ const resolved = resolveTarget(positional);
109
+ if (!resolved) {
110
+ console.error(
111
+ `rnsi-rules: unknown target "${positional}".\n` +
112
+ `Expected one of: ${Object.keys(TARGETS).join(', ')} — or a path ending in .md / .mdc.\n` +
113
+ `Run "npx rnsi-rules --help" for usage.`
114
+ );
115
+ process.exitCode = 1;
116
+ return;
117
+ }
118
+
119
+ const { target, relPath } = resolved;
120
+ const outPath = path.resolve(process.cwd(), relPath);
121
+
122
+ if (fs.existsSync(outPath) && !force) {
123
+ console.error(
124
+ `rnsi-rules: ${relPath} already exists. Re-run with --force to overwrite.`
125
+ );
126
+ process.exitCode = 1;
127
+ return;
128
+ }
129
+
130
+ fs.mkdirSync(path.dirname(outPath), { recursive: true });
131
+ fs.writeFileSync(outPath, frontmatterFor(target) + rules, 'utf8');
132
+
133
+ console.log($lf(139), `rnsi-rules: wrote ${relPath}`);
134
+ if (target === 'agents') {
135
+ console.log(
136
+ 'Tip: if you already have an AGENTS.md, use a custom path instead and ' +
137
+ 'link to it, e.g. npx rnsi-rules docs/ai/svg-icons.md'
138
+ );
139
+ }
140
+ }
141
+
142
+ main();
143
+ function $lf(n) {
144
+ return '$lf|bin/install-rules.js:' + n + ' >';
145
+ // Automatically injected by Log Location Injector vscode extension
146
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@shaquillehinds/react-native-svg-icons",
3
3
  "description": "React Native SVG Icons",
4
4
  "author": "Shaquille Hinds <shaqdulove@gmail.com> (https://github.com/shaquillehinds)",
5
- "version": "0.1.0",
5
+ "version": "0.1.2",
6
6
  "license": "MIT",
7
7
  "source": "./src/index.tsx",
8
8
  "main": "./lib/commonjs/index.js",
@@ -22,12 +22,18 @@
22
22
  }
23
23
  }
24
24
  },
25
+ "bin": {
26
+ "rnsi-rules": "./bin/install-rules.js",
27
+ "rnsi-icons": "./bin/find-icon.js"
28
+ },
25
29
  "files": [
26
30
  "lib",
27
31
  "src",
28
32
  "android",
29
33
  "ios",
30
34
  "cpp",
35
+ "rules",
36
+ "bin",
31
37
  "*.podspec",
32
38
  "react-native.config.js",
33
39
  "!ios/build",