@featherk/icons 0.15.8 → 0.16.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.
Files changed (32) hide show
  1. package/README.md +15 -3
  2. package/dist/docs-manifest.d.ts +1 -0
  3. package/dist/docs-manifest.js +7 -5
  4. package/dist/fontawesome/build.cjs +1 -2
  5. package/dist/fontawesome/build.d.ts +1 -1
  6. package/dist/fontawesome/build.mjs +2 -3
  7. package/dist/fontawesome/catalog.cjs +0 -13
  8. package/dist/fontawesome/catalog.d.ts +0 -8
  9. package/dist/fontawesome/catalog.mjs +0 -13
  10. package/dist/fontawesome/chunks/{generate-BBurrhLv.cjs → generate-B_FxftR7.cjs} +12 -1
  11. package/dist/fontawesome/chunks/{generate-Zq9q2YZD.mjs → generate-DF9R65sV.mjs} +13 -2
  12. package/dist/fontawesome/chunks/manifest-CSRIDvaR.mjs +56 -0
  13. package/dist/fontawesome/chunks/manifest-Yjw62jxG.cjs +55 -0
  14. package/dist/fontawesome/cli.cjs +23 -26
  15. package/dist/fontawesome/cli.mjs +23 -26
  16. package/dist/fontawesome/generate.d.ts +7 -0
  17. package/dist/fontawesome/manifest.d.ts +36 -0
  18. package/dist/fontawesome/setup.cjs +185 -180
  19. package/dist/fontawesome/setup.d.ts +2 -2
  20. package/dist/fontawesome/setup.mjs +186 -181
  21. package/dist/fontawesome/vite.cjs +64 -28
  22. package/dist/fontawesome/vite.d.ts +26 -5
  23. package/dist/fontawesome/vite.mjs +65 -29
  24. package/docs/ICONS.md +1 -1
  25. package/docs/fontawesome/CreateFontAwesomeManifest.md +1 -1
  26. package/docs/fontawesome/FontAwesome.md +48 -44
  27. package/docs/fontawesome/FontAwesomeCLI.md +14 -19
  28. package/docs/fontawesome/FontAwesomeDeveloperSetup.md +134 -0
  29. package/docs/fontawesome/LICENSING.md +107 -66
  30. package/package.json +1 -1
  31. package/dist/fontawesome/chunks/manifest-BB3q10t1.mjs +0 -20
  32. package/dist/fontawesome/chunks/manifest-C15Xa22L.cjs +0 -19
@@ -1,10 +1,10 @@
1
1
  import { spawnSync } from "node:child_process";
2
2
  import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync } from "node:fs";
3
- import { resolve, relative } from "node:path";
3
+ import { resolve } from "node:path";
4
4
  import { emitKeypressEvents } from "node:readline";
5
5
  import { parseArgs } from "node:util";
6
6
  import { fontAwesomeCatalog, resolveFontAwesomeKeys } from "./catalog.mjs";
7
- import { r as readFontAwesomeManifest } from "./chunks/manifest-BB3q10t1.mjs";
7
+ import { f as fontAwesomeProSourcesDir, i as isFontAwesomeIsolated, r as readFontAwesomeManifest, a as fontAwesomeManifestKeys } from "./chunks/manifest-CSRIDvaR.mjs";
8
8
  const tokenVariable = "FONTAWESOME_PACKAGE_TOKEN";
9
9
  const tokenPlaceholder = `\${${tokenVariable}}`;
10
10
  const registry = "https://npm.fontawesome.com/";
@@ -23,30 +23,35 @@ const workspaceVariables = [
23
23
  "NPM_CONFIG_WORKSPACES"
24
24
  ];
25
25
  const usage = `Usage:
26
- featherk-fontawesome-setup (--manifest <icons.json> | --keys <a,b>) [--free-only]
27
- featherk-fontawesome-setup --source-root <dir> [--refresh-lock]
28
- featherk-fontawesome-setup --source-root <dir> --init (--manifest <icons.json> | --keys <a,b>) [--force]
26
+ featherk-fontawesome-setup --manifest <icons.json> [--free-only | --pro-in-app]
27
+ featherk-fontawesome-setup
29
28
 
30
- Default (Free + Pro): run once from the application root on a developer
31
- machine. Adds the @fortawesome registry lines to .npmrc (token placeholder
32
- only) and installs exact pins for all selected keys as devDependencies.
33
- Commit .npmrc, package.json, and package-lock.json. Later installs, including
34
- CI, give ${tokenVariable} only to "npm ci --ignore-scripts", then run any
35
- needed install scripts (npm rebuild for dependencies, plus the app's own) and
36
- builds without it. Do not export the token persistently.
29
+ Run from the application root. The manifest contains
30
+ { "free": [keys], "pro": [keys] }, the same file the Vite plugin reads.
37
31
 
38
- --free-only: Free keys only from public npm. No .npmrc changes, no token.
32
+ --manifest (default): installs exact Free pins into the app's devDependencies
33
+ from public npm, and writes exact Pro pins into an isolated private source
34
+ project, ${fontAwesomeProSourcesDir}/, then installs it with the token. The
35
+ app's own install never needs the token. Rerun after changing the manifest.
36
+ Commit package.json, package-lock.json, and ${fontAwesomeProSourcesDir}/
37
+ (its node_modules is ignored).
39
38
 
40
- --source-root <dir>: install licensed packages into an isolated private
41
- source project instead (npm ci when its lockfile exists). --init scaffolds
42
- that project; with --force, a lockfile for different dependencies is removed
43
- so the next install regenerates it. --refresh-lock runs npm install to update
44
- the lockfile after editing package.json by hand. In CI, --init and
45
- --refresh-lock are refused and a lockfile is required.
39
+ No arguments: installs ${fontAwesomeProSourcesDir}/ from its committed
40
+ lockfile with the token, for CI and fresh clones. Run it after the app's own
41
+ "npm ci".
42
+
43
+ --free-only: Free keys only from public npm. No token, no source project.
44
+
45
+ --pro-in-app: installs Free and Pro pins into the app's own devDependencies
46
+ and routes @fortawesome to the Pro registry in the app's .npmrc (token
47
+ placeholder only). Every install of the app, including CI, then needs the
48
+ token for "npm ci --ignore-scripts". Use only when the isolated project is not
49
+ an option.
46
50
 
47
51
  The token comes from ${tokenVariable} or a hidden prompt in an interactive
48
- terminal. App-root setup changes package.json and is refused in CI
49
- (CI, TEAMCITY_VERSION, or GITHUB_ACTIONS is set).`;
52
+ terminal. --manifest setup changes package.json and is refused in CI
53
+ (CI, TEAMCITY_VERSION, or GITHUB_ACTIONS is set). Do not export the token
54
+ persistently.`;
50
55
  function promptForTerminalToken() {
51
56
  const input = process.stdin;
52
57
  if (!input.isTTY || typeof input.setRawMode !== "function") {
@@ -125,19 +130,13 @@ function requireNpm(context) {
125
130
  return npmCli;
126
131
  }
127
132
  async function readKeys(values, context) {
128
- if (values.keys && values.manifest) {
129
- throw new Error("Provide either --keys or --manifest, not both.");
130
- }
131
- if (values.keys) {
132
- return values.keys.split(",").map((key) => key.trim()).filter(Boolean);
133
- }
134
133
  if (!values.manifest) {
135
- throw new Error("Provide --manifest or --keys. Use --help for usage.");
134
+ throw new Error("Provide --manifest. Use --help for usage.");
136
135
  }
137
- const { free, pro } = await readFontAwesomeManifest(
136
+ const manifest = await readFontAwesomeManifest(
138
137
  resolve(context.cwd, values.manifest)
139
138
  );
140
- return [...free, ...pro];
139
+ return fontAwesomeManifestKeys(manifest);
141
140
  }
142
141
  function resolvePins(keys) {
143
142
  const tiers = new Map(
@@ -192,54 +191,11 @@ function checkNpmrc(config, file) {
192
191
  }
193
192
  return { fontAwesomeRegistry, hasAuth };
194
193
  }
195
- async function setupAppRoot(values, context) {
196
- const { log } = context;
197
- if (context.isCi) {
198
- throw new Error(
199
- `App-root setup changes package.json and is a local, one-time step. In CI, give ${tokenVariable} only to "npm ci --ignore-scripts", then run needed install scripts and the build without it.`
200
- );
201
- }
202
- const appRoot = context.cwd;
203
- if (!existsSync(resolve(appRoot, "package.json"))) {
204
- throw new Error(
205
- "Run this command from the application root (package.json not found)."
206
- );
207
- }
208
- const freeOnly = Boolean(values["free-only"]);
209
- const pins = resolvePins(await readKeys(values, context));
210
- const proPins = [...pins.values()].filter((pin) => pin.tier === "pro");
211
- if (freeOnly && proPins.length) {
212
- throw new Error(
213
- `--free-only cannot install Pro keys: ${proPins.map((pin) => pin.key).join(", ")}.`
214
- );
215
- }
216
- if (!pins.size) {
217
- throw new Error("No Font Awesome keys selected.");
218
- }
219
- const npmrcPath = resolve(appRoot, ".npmrc");
220
- const config = existsSync(npmrcPath) ? readFileSync(npmrcPath, "utf8") : "";
221
- const { fontAwesomeRegistry, hasAuth } = checkNpmrc(config, ".npmrc");
222
- if (freeOnly && fontAwesomeRegistry) {
223
- throw new Error(
224
- `.npmrc routes @fortawesome to ${fontAwesomeRegistry}, so this app is set up for Pro. Run without --free-only.`
225
- );
226
- }
194
+ function installIntoApp(pins, pro, token, context) {
227
195
  const npmCli = requireNpm(context);
228
196
  const environment = { ...context.env };
229
- if (!freeOnly) {
230
- environment[tokenVariable] = await readToken(context);
231
- const missing = [];
232
- if (!fontAwesomeRegistry) missing.push(npmrcLines[0], npmrcLines[1]);
233
- if (!hasAuth) missing.push(npmrcLines[2], npmrcLines[3]);
234
- if (missing.length) {
235
- const separator = config && !config.endsWith("\n") ? "\n" : "";
236
- writeFileSync(npmrcPath, `${config}${separator}${missing.join("\n")}
237
- `);
238
- log(
239
- `${config ? "Updated" : "Created"} .npmrc with the Font Awesome registry and token placeholder.`
240
- );
241
- }
242
- }
197
+ delete environment[tokenVariable];
198
+ if (pro && token) environment[tokenVariable] = token;
243
199
  const specs = [...pins].map(([name, pin]) => `${name}@${pin.spec}`);
244
200
  const status = context.runNpm({
245
201
  npmCli,
@@ -250,27 +206,18 @@ async function setupAppRoot(values, context) {
250
206
  "--ignore-scripts",
251
207
  "--no-audit",
252
208
  "--no-fund",
253
- ...freeOnly ? [] : [pinRegistry],
209
+ ...pro ? [pinRegistry] : [],
254
210
  ...specs
255
211
  ],
256
- cwd: appRoot,
212
+ cwd: context.cwd,
257
213
  env: environment
258
214
  });
259
- if (status !== 0) return status;
260
- log(`Installed ${specs.length} Font Awesome package(s): ${specs.join(" ")}`);
261
- log(
262
- "Lifecycle scripts were skipped. If needed, run npm rebuild for dependency scripts and the app's own scripts (e.g. npm run prepare --if-present)."
263
- );
264
- if (freeOnly) {
265
- log(
266
- "Next: commit package.json and package-lock.json. Keep the Vite plugin's allowPro unset (Free only); no CI token is needed."
267
- );
268
- } else {
269
- log(
270
- `Next: commit .npmrc, package.json, and package-lock.json. Set allowPro: true in the Vite plugin (no sourceRoot). Later installs, including CI, give ${tokenVariable} only to "npm ci --ignore-scripts"; run needed install scripts and builds without it. See LICENSING.md for the TeamCity setup.`
215
+ if (status === 0) {
216
+ context.log(
217
+ `Installed ${specs.length} Font Awesome package(s) into the app: ${specs.join(" ")}`
271
218
  );
272
219
  }
273
- return 0;
220
+ return status;
274
221
  }
275
222
  function readDependencies(packageJsonPath) {
276
223
  try {
@@ -284,109 +231,61 @@ function readDependencies(packageJsonPath) {
284
231
  return void 0;
285
232
  }
286
233
  }
287
- async function initSourceProject(sourceRoot, values, context) {
288
- const { log, display } = context;
289
- if (context.isCi) {
290
- throw new Error(
291
- "--init is a local, one-time step. Commit the scaffolded source project instead of generating it in CI."
292
- );
293
- }
294
- const pins = resolvePins(await readKeys(values, context));
295
- const dependencies = {};
296
- const skipped = [];
297
- for (const [name, pin] of pins) {
298
- if (pin.tier === "pro") dependencies[name] = pin.spec;
299
- else skipped.push(pin.key);
300
- }
301
- if (!Object.keys(dependencies).length) {
302
- throw new Error(
303
- "No Pro keys selected. Free packages belong in the application's own devDependencies."
304
- );
305
- }
306
- const sortedDependencies = Object.fromEntries(
307
- Object.entries(dependencies).sort()
234
+ function writeSourceProject(sourceRoot, proPins, context) {
235
+ const dependencies = Object.fromEntries(
236
+ [...proPins].map(([name, pin]) => [name, pin.spec]).sort()
308
237
  );
238
+ const created = !existsSync(resolve(sourceRoot, "package.json"));
239
+ const lockfilePath = resolve(sourceRoot, "package-lock.json");
240
+ const removeStaleLockfile = existsSync(lockfilePath) && readDependencies(resolve(sourceRoot, "package.json")) !== JSON.stringify(dependencies);
309
241
  const files = {
310
242
  ".npmrc": `${npmrcLines.join("\n")}
311
243
  `,
312
244
  ".gitignore": "node_modules/\n",
313
245
  "package.json": `${JSON.stringify(
314
246
  {
315
- name: "fontawesome-pro-sources",
247
+ name: fontAwesomeProSourcesDir,
316
248
  version: "0.0.0",
317
249
  private: true,
318
- dependencies: sortedDependencies
250
+ dependencies
319
251
  },
320
252
  null,
321
253
  2
322
254
  )}
323
255
  `
324
256
  };
325
- const existing = Object.keys(files).filter(
326
- (name) => existsSync(resolve(sourceRoot, name))
327
- );
328
- if (existing.length && !values.force) {
329
- throw new Error(
330
- `${display(sourceRoot)} already contains ${existing.join(", ")}. Use --force to overwrite.`
331
- );
332
- }
333
- const lockfilePath = resolve(sourceRoot, "package-lock.json");
334
- const removeStaleLockfile = existsSync(lockfilePath) && readDependencies(resolve(sourceRoot, "package.json")) !== JSON.stringify(sortedDependencies);
335
257
  mkdirSync(sourceRoot, { recursive: true });
336
258
  for (const [name, content] of Object.entries(files)) {
337
259
  writeFileSync(resolve(sourceRoot, name), content);
338
260
  }
339
261
  if (removeStaleLockfile) rmSync(lockfilePath);
340
- if (skipped.length) {
341
- log(
342
- `Skipped Free keys (install them in the application instead): ${skipped.join(", ")}`
343
- );
344
- }
345
- log(
346
- `Scaffolded ${display(sourceRoot)} with ${Object.keys(dependencies).length} Pro package(s).`
262
+ context.log(
263
+ `${created ? "Created" : "Updated"} ${fontAwesomeProSourcesDir}/ with ${proPins.size} Pro package(s).`
347
264
  );
348
265
  if (removeStaleLockfile) {
349
- log(
350
- `Removed ${display(sourceRoot)}/package-lock.json because the dependencies changed; the next install regenerates it.`
266
+ context.log(
267
+ `Removed ${fontAwesomeProSourcesDir}/package-lock.json because the Pro pins changed; this install regenerates it.`
351
268
  );
352
269
  }
353
- log(
354
- "Next: run this command with --source-root and without --init, then commit the source project and its package-lock.json."
355
- );
356
- return 0;
357
270
  }
358
- async function installSourceProject(sourceRoot, values, context) {
359
- const { log, display } = context;
271
+ async function installSourceProject(sourceRoot, token, context) {
360
272
  const npmCli = requireNpm(context);
361
- for (const name of ["package.json", ".npmrc"]) {
362
- if (!existsSync(resolve(sourceRoot, name))) {
363
- throw new Error(
364
- `${display(sourceRoot)}/${name} was not found. Check --source-root, or scaffold the project with --init.`
365
- );
366
- }
367
- }
368
- const npmrc = `${display(sourceRoot)}/.npmrc`;
273
+ const npmrc = `${fontAwesomeProSourcesDir}/.npmrc`;
369
274
  const { fontAwesomeRegistry, hasAuth } = checkNpmrc(
370
275
  readFileSync(resolve(sourceRoot, ".npmrc"), "utf8"),
371
276
  npmrc
372
277
  );
373
278
  if (!fontAwesomeRegistry || !hasAuth) {
374
279
  throw new Error(
375
- `${npmrc} must contain @fortawesome:registry=${registry} and ${authKey}=${tokenPlaceholder}. Scaffold it with --init.`
280
+ `${npmrc} must contain @fortawesome:registry=${registry} and ${authKey}=${tokenPlaceholder}. Rerun with --manifest to rewrite it.`
376
281
  );
377
282
  }
378
- const hasLockfile = existsSync(resolve(sourceRoot, "package-lock.json"));
379
- if (context.isCi && !hasLockfile) {
283
+ const locked = existsSync(resolve(sourceRoot, "package-lock.json"));
284
+ if (context.isCi && !locked) {
380
285
  throw new Error(
381
- `${display(sourceRoot)}/package-lock.json is required in CI. Install locally first and commit the lockfile.`
286
+ `${fontAwesomeProSourcesDir}/package-lock.json is required in CI. Run setup with --manifest locally first and commit the lockfile.`
382
287
  );
383
288
  }
384
- if (context.isCi && values["refresh-lock"]) {
385
- throw new Error(
386
- "--refresh-lock updates the lockfile and is a local step. In CI, install from the committed lockfile."
387
- );
388
- }
389
- const locked = hasLockfile && !values["refresh-lock"];
390
289
  const environment = {
391
290
  ...context.env,
392
291
  [tokenVariable]: await readToken(context)
@@ -406,12 +305,119 @@ async function installSourceProject(sourceRoot, values, context) {
406
305
  env: environment
407
306
  });
408
307
  if (status !== 0) return status;
409
- const lockfile = `${display(sourceRoot)}/package-lock.json`;
410
- log(
308
+ const lockfile = `${fontAwesomeProSourcesDir}/package-lock.json`;
309
+ context.log(
411
310
  locked ? `Pro sources installed from ${lockfile}.` : `Pro sources installed. Review and commit ${lockfile}.`
412
311
  );
413
312
  return 0;
414
313
  }
314
+ async function setupFromManifest(values, context) {
315
+ const { log } = context;
316
+ const freeOnly = Boolean(values["free-only"]);
317
+ const proInApp = Boolean(values["pro-in-app"]);
318
+ if (freeOnly && proInApp) {
319
+ throw new Error("Use either --free-only or --pro-in-app, not both.");
320
+ }
321
+ if (context.isCi) {
322
+ throw new Error(
323
+ `--manifest setup changes package.json and is a local step. In CI, run the app's own "npm ci", then featherk-fontawesome-setup without arguments to install ${fontAwesomeProSourcesDir}/.`
324
+ );
325
+ }
326
+ const appRoot = context.cwd;
327
+ if (!existsSync(resolve(appRoot, "package.json"))) {
328
+ throw new Error(
329
+ "Run this command from the application root (package.json not found)."
330
+ );
331
+ }
332
+ const pins = resolvePins(await readKeys(values, context));
333
+ if (!pins.size) {
334
+ throw new Error("No Font Awesome keys selected.");
335
+ }
336
+ const freePins = new Map([...pins].filter(([, pin]) => pin.tier !== "pro"));
337
+ const proPins = new Map([...pins].filter(([, pin]) => pin.tier === "pro"));
338
+ if (freeOnly && proPins.size) {
339
+ throw new Error(
340
+ `--free-only cannot install Pro keys: ${[...proPins.values()].map((pin) => pin.key).join(", ")}.`
341
+ );
342
+ }
343
+ const npmrcPath = resolve(appRoot, ".npmrc");
344
+ const config = existsSync(npmrcPath) ? readFileSync(npmrcPath, "utf8") : "";
345
+ const { fontAwesomeRegistry, hasAuth } = checkNpmrc(config, ".npmrc");
346
+ const sourceRoot = resolve(appRoot, fontAwesomeProSourcesDir);
347
+ const isolated = isFontAwesomeIsolated(appRoot);
348
+ if (proInApp && isolated) {
349
+ throw new Error(
350
+ `${fontAwesomeProSourcesDir}/ exists, so this app keeps Pro in the isolated source project. Run without --pro-in-app, or remove ${fontAwesomeProSourcesDir}/ first.`
351
+ );
352
+ }
353
+ if (!proInApp && fontAwesomeRegistry) {
354
+ throw new Error(
355
+ `.npmrc routes @fortawesome to ${fontAwesomeRegistry}, so this app installs Pro in the app itself. Rerun with --pro-in-app.`
356
+ );
357
+ }
358
+ if (freeOnly && isolated) {
359
+ throw new Error(
360
+ `${fontAwesomeProSourcesDir}/ exists, so this app uses Pro. Run without --free-only, or remove ${fontAwesomeProSourcesDir}/ first.`
361
+ );
362
+ }
363
+ if (proInApp) {
364
+ const token = proPins.size ? await readToken(context) : void 0;
365
+ if (proPins.size) {
366
+ const missing = [];
367
+ if (!fontAwesomeRegistry) missing.push(npmrcLines[0], npmrcLines[1]);
368
+ if (!hasAuth) missing.push(npmrcLines[2], npmrcLines[3]);
369
+ if (missing.length) {
370
+ const separator = config && !config.endsWith("\n") ? "\n" : "";
371
+ writeFileSync(
372
+ npmrcPath,
373
+ `${config}${separator}${missing.join("\n")}
374
+ `
375
+ );
376
+ log(
377
+ `${config ? "Updated" : "Created"} .npmrc with the Font Awesome registry and token placeholder.`
378
+ );
379
+ }
380
+ }
381
+ const status2 = installIntoApp(pins, proPins.size > 0, token, context);
382
+ if (status2 !== 0) return status2;
383
+ log(lifecycleNote);
384
+ log(
385
+ `Next: commit .npmrc, package.json, and package-lock.json. Configure the Vite plugin with { manifest }. Every later install, including CI, gives ${tokenVariable} only to "npm ci --ignore-scripts"; run needed install scripts and builds without it.`
386
+ );
387
+ return 0;
388
+ }
389
+ if (freePins.size) {
390
+ const status2 = installIntoApp(freePins, false, void 0, context);
391
+ if (status2 !== 0) return status2;
392
+ log(lifecycleNote);
393
+ }
394
+ if (!proPins.size) {
395
+ if (isolated) {
396
+ log(
397
+ `The manifest has no Pro keys; ${fontAwesomeProSourcesDir}/ is no longer needed and can be removed.`
398
+ );
399
+ }
400
+ log(
401
+ "Next: commit package.json and package-lock.json. Configure the Vite plugin with { manifest }; no token is needed."
402
+ );
403
+ return 0;
404
+ }
405
+ writeSourceProject(sourceRoot, proPins, context);
406
+ const status = await installSourceProject(sourceRoot, void 0, context);
407
+ if (status !== 0) return status;
408
+ log(
409
+ `Next: commit package.json, package-lock.json, and ${fontAwesomeProSourcesDir}/. Configure the Vite plugin with { manifest }; builds include Pro icons wherever ${fontAwesomeProSourcesDir}/ is installed. In CI, run the app's "npm ci" without the token, then featherk-fontawesome-setup with ${tokenVariable}, then the normal build.`
410
+ );
411
+ return 0;
412
+ }
413
+ const lifecycleNote = "Lifecycle scripts were skipped. If needed, run npm rebuild for dependency scripts and the app's own scripts (e.g. npm run prepare --if-present).";
414
+ const removedFlags = [
415
+ "--keys",
416
+ "--source-root",
417
+ "--init",
418
+ "--force",
419
+ "--refresh-lock"
420
+ ];
415
421
  async function runFontAwesomeSetup(args, io = {}) {
416
422
  const cwd = io.cwd ?? process.cwd();
417
423
  const env = io.env ?? process.env;
@@ -423,20 +429,23 @@ async function runFontAwesomeSetup(args, io = {}) {
423
429
  isCi: Boolean(env.CI) && env.CI !== "false" || Boolean(env.TEAMCITY_VERSION || env.GITHUB_ACTIONS),
424
430
  log: io.stdout ?? console.log,
425
431
  promptForToken: io.promptForToken ?? promptForTerminalToken,
426
- runNpm: io.runNpm ?? spawnNpm,
427
- display: (path) => relative(cwd, path) || "."
432
+ runNpm: io.runNpm ?? spawnNpm
428
433
  };
429
434
  try {
435
+ const removed = removedFlags.find(
436
+ (flag) => args.some((arg) => arg === flag || arg.startsWith(`${flag}=`))
437
+ );
438
+ if (removed) {
439
+ throw new Error(
440
+ `${removed} was removed in 0.16.0. Run setup with --manifest; Pro sources always live in ${fontAwesomeProSourcesDir}/, and rerunning with --manifest updates them. Use --help for usage.`
441
+ );
442
+ }
430
443
  const { values } = parseArgs({
431
444
  args: [...args],
432
445
  options: {
433
- "source-root": { type: "string" },
434
446
  "free-only": { type: "boolean" },
435
- init: { type: "boolean" },
436
- keys: { type: "string" },
447
+ "pro-in-app": { type: "boolean" },
437
448
  manifest: { type: "string" },
438
- force: { type: "boolean" },
439
- "refresh-lock": { type: "boolean" },
440
449
  help: { type: "boolean", short: "h" }
441
450
  },
442
451
  strict: true,
@@ -446,26 +455,22 @@ async function runFontAwesomeSetup(args, io = {}) {
446
455
  context.log(usage);
447
456
  return 0;
448
457
  }
449
- if (values["source-root"] === void 0) {
450
- if (values.init || values.force || values["refresh-lock"]) {
451
- throw new Error(
452
- "--init, --force, and --refresh-lock apply only with --source-root."
453
- );
454
- }
455
- return await setupAppRoot(values, context);
458
+ if (values.manifest !== void 0) {
459
+ return await setupFromManifest(values, context);
456
460
  }
457
- if (values["free-only"]) {
458
- throw new Error(
459
- "--free-only applies only to app-root setup; an isolated source project holds Pro packages."
460
- );
461
+ if (values["free-only"] || values["pro-in-app"]) {
462
+ throw new Error("--free-only and --pro-in-app require --manifest.");
461
463
  }
462
- if (values.init && values["refresh-lock"]) {
464
+ if (!isFontAwesomeIsolated(cwd)) {
463
465
  throw new Error(
464
- "--refresh-lock applies to the install step, not --init."
466
+ `${fontAwesomeProSourcesDir}/package.json was not found. Run from the application root; for first-time setup, run with --manifest <icons.json>.`
465
467
  );
466
468
  }
467
- const sourceRoot = resolve(cwd, values["source-root"]);
468
- return values.init ? await initSourceProject(sourceRoot, values, context) : await installSourceProject(sourceRoot, values, context);
469
+ return await installSourceProject(
470
+ resolve(cwd, fontAwesomeProSourcesDir),
471
+ void 0,
472
+ context
473
+ );
469
474
  } catch (error) {
470
475
  stderr(error instanceof Error ? error.message : "Unknown error");
471
476
  return 1;
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const node_path = require("node:path");
4
4
  const promises = require("node:fs/promises");
5
- const fontawesome_catalog = require("./catalog.cjs");
6
- const generate = require("./chunks/generate-BBurrhLv.cjs");
5
+ const generate = require("./chunks/generate-B_FxftR7.cjs");
6
+ const manifest = require("./chunks/manifest-Yjw62jxG.cjs");
7
7
  const virtualId = "virtual:featherk/fontawesome";
8
8
  const resolvedId = `\0${virtualId}`;
9
9
  function dependencyKey(file) {
@@ -11,20 +11,56 @@ function dependencyKey(file) {
11
11
  return process.platform === "win32" ? path.toLowerCase() : path;
12
12
  }
13
13
  function featherkFontAwesome(options) {
14
+ const legacy = options;
15
+ if (legacy.keys !== void 0 || legacy.allowPro !== void 0) {
16
+ throw new Error(
17
+ 'Font Awesome Vite options "keys" and "allowPro" were removed in 0.16.0. List the keys in a { free, pro } manifest and pass { manifest: "fontawesome.keys.json" }.'
18
+ );
19
+ }
20
+ if (legacy.sourceRoot !== void 0 || legacy.proMode !== void 0) {
21
+ throw new Error(
22
+ `Font Awesome Vite options "sourceRoot" and "proMode" were removed in 0.16.0. Pro sources always live in ${manifest.fontAwesomeProSourcesDir}/ and are used wherever it is installed; pass only { manifest }.`
23
+ );
24
+ }
25
+ if (typeof options.manifest !== "string" || !options.manifest.trim()) {
26
+ throw new Error(
27
+ 'Font Awesome Vite options require a manifest path, such as { manifest: "fontawesome.keys.json" }'
28
+ );
29
+ }
14
30
  let root = node_path.resolve(options.root ?? process.cwd());
31
+ let logger;
15
32
  let generation;
16
33
  let dependencies = /* @__PURE__ */ new Set();
17
- function regenerate() {
18
- generation = generate.generateFaIcons({
19
- keys: options.keys,
20
- root,
21
- sourceRoot: options.sourceRoot,
22
- allowPro: options.allowPro,
23
- virtualTypesFile: options.virtualTypesFile === false ? void 0 : options.virtualTypesFile ?? "src/featherk-fontawesome.d.ts"
24
- }).then((result) => {
25
- dependencies = new Set(result.dependencies.map(dependencyKey));
34
+ let watchFiles = [];
35
+ async function resolveSelection() {
36
+ const manifestFile = node_path.resolve(root, options.manifest);
37
+ const manifest$1 = await manifest.readFontAwesomeManifest(manifestFile).catch(
38
+ (error) => {
39
+ throw new Error(
40
+ `Cannot read Font Awesome manifest ${node_path.relative(root, manifestFile) || manifestFile}: ${error instanceof Error ? error.message : String(error)}`
41
+ );
42
+ }
43
+ );
44
+ return {
45
+ ...manifest.selectFontAwesomeManifestKeys(manifest$1, root),
46
+ // Match the real paths that handleHotUpdate compares against.
47
+ manifestFile: await promises.realpath(manifestFile)
48
+ };
49
+ }
50
+ function regenerate(selection) {
51
+ generation = (async () => {
52
+ const selected = selection ?? await resolveSelection();
53
+ const result = await generate.generateFaIcons({
54
+ keys: selected.keys,
55
+ root,
56
+ sourceRoot: selected.sourceRoot,
57
+ allowPro: selected.allowPro,
58
+ virtualTypesFile: options.virtualTypesFile === false ? void 0 : options.virtualTypesFile ?? "src/featherk-fontawesome.d.ts"
59
+ });
60
+ watchFiles = [...result.dependencies, selected.manifestFile];
61
+ dependencies = new Set(watchFiles.map(dependencyKey));
26
62
  return result;
27
- });
63
+ })();
28
64
  return generation;
29
65
  }
30
66
  return {
@@ -32,20 +68,12 @@ function featherkFontAwesome(options) {
32
68
  enforce: "pre",
33
69
  async configResolved(config) {
34
70
  root = node_path.resolve(config.root, options.root ?? ".");
35
- const installCommand = options.keys === void 0 ? void 0 : fontawesome_catalog.getFontAwesomeInstallCommand(options.keys, {
36
- allowPro: options.allowPro
37
- });
38
- if (installCommand) {
39
- console.info(
40
- `[featherk-fontawesome] Install selected source packages with:
41
- ${installCommand}`
42
- );
43
- }
44
- await regenerate();
71
+ if (config.command === "build") logger = config.logger;
72
+ await regenerate(await resolveSelection());
45
73
  },
46
74
  async buildStart() {
47
- const result = await regenerate();
48
- for (const file of result.dependencies) this.addWatchFile(file);
75
+ await regenerate();
76
+ for (const file of watchFiles) this.addWatchFile(file);
49
77
  },
50
78
  resolveId(id) {
51
79
  return id === virtualId ? resolvedId : void 0;
@@ -55,14 +83,14 @@ ${installCommand}`
55
83
  return (await (generation ?? regenerate())).moduleCode;
56
84
  },
57
85
  async configureServer(server) {
58
- const result = await (generation ?? regenerate());
59
- server.watcher.add(result.dependencies);
86
+ await (generation ?? regenerate());
87
+ server.watcher.add(watchFiles);
60
88
  },
61
89
  async handleHotUpdate(context) {
62
90
  const file = await promises.realpath(context.file).catch(() => context.file);
63
91
  if (!dependencies.has(dependencyKey(file))) return void 0;
64
- const result = await regenerate();
65
- context.server.watcher.add(result.dependencies);
92
+ await regenerate();
93
+ context.server.watcher.add(watchFiles);
66
94
  const module2 = context.server.moduleGraph.getModuleById(resolvedId);
67
95
  if (module2) context.server.moduleGraph.invalidateModule(module2);
68
96
  context.server.ws.send({ type: "full-reload" });
@@ -77,6 +105,14 @@ ${installCommand}`
77
105
  source: result.notices
78
106
  });
79
107
  }
108
+ },
109
+ async closeBundle() {
110
+ const result = await generation?.catch(() => void 0);
111
+ if (logger && result) {
112
+ logger.info(
113
+ `[featherk-fontawesome] Generated ${generate.summarizeFaIcons(result.provenance)}`
114
+ );
115
+ }
80
116
  }
81
117
  };
82
118
  }