better-asset 0.1.1 → 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.
package/README.md CHANGED
@@ -94,15 +94,15 @@ Add a `$schema` key for editor autocompletion:
94
94
 
95
95
  ### Asset Fields
96
96
 
97
- | Field | Type | Required | Default | Description |
98
- | ------------- | ------- | -------- | ------- | -------------------------------------------- |
99
- | `name` | string | yes | — | Base name for generated files |
100
- | `source` | string | yes | — | Source filename (relative to `source_dir`) |
101
- | `sizes` | array | yes | — | Sizes to generate |
102
- | `destination` | string | yes | — | Output directory (relative to project root) |
103
- | `format` | string | no | `"png"` | Output format: `png`, `webp`, `jpeg`, `avif` |
104
- | `sizeInName` | boolean | no | auto | Force include/exclude size in filename |
105
- | `ico` | object | no | — | Generate a `favicon.ico` |
97
+ | Field | Type | Required | Default | Description |
98
+ | ------------- | ----------------- | -------- | ------- | -------------------------------------------- |
99
+ | `name` | string | yes | — | Base name for generated files |
100
+ | `source` | string | yes | — | Source filename (relative to `source_dir`) |
101
+ | `sizes` | array | yes | — | Sizes to generate |
102
+ | `destination` | string | yes | — | Output directory (relative to project root) |
103
+ | `format` | string | no | `"png"` | Output format: `png`, `webp`, `jpeg`, `avif` |
104
+ | `sizeInName` | boolean | no | auto | Force include/exclude size in filename |
105
+ | `ico` | boolean \| object | no | — | Generate a `favicon.ico` |
106
106
 
107
107
  ## Size Rules
108
108
 
@@ -134,7 +134,14 @@ Override per asset:
134
134
 
135
135
  ## ICO Generation
136
136
 
137
- Add an `ico` object to generate a real `favicon.ico`:
137
+ Use `ico` as either a boolean shortcut or an object:
138
+
139
+ ```json
140
+ { "ico": true }
141
+ { "ico": false }
142
+ ```
143
+
144
+ Or use the object form for more control:
138
145
 
139
146
  ```json
140
147
  {
@@ -145,10 +152,10 @@ Add an `ico` object to generate a real `favicon.ico`:
145
152
  }
146
153
  ```
147
154
 
148
- | Field | Type | Default | Description |
149
- | ---------- | ------- | ------- | -------------------------------------- |
150
- | `required` | boolean | — | Whether to generate the `.ico` file |
151
- | `size` | number | `64` | Size of the embedded PNG in the `.ico` |
155
+ | Field | Type | Required | Default | Description |
156
+ | ---------- | ------- | -------- | ------- | -------------------------------------- |
157
+ | `required` | boolean | yes | — | Whether to generate the `.ico` file |
158
+ | `size` | number | no | `64` | Size of the embedded PNG in the `.ico` |
152
159
 
153
160
  ## License
154
161
 
@@ -62,21 +62,29 @@
62
62
  "description": "Force include/exclude size in filename. Default: included when multiple sizes, omitted for single size."
63
63
  },
64
64
  "ico": {
65
- "type": "object",
66
- "description": "Generate a favicon.ico file from this asset.",
67
- "required": ["required"],
68
- "properties": {
69
- "required": {
65
+ "oneOf": [
66
+ {
70
67
  "type": "boolean",
71
- "description": "Whether to generate the .ico file."
68
+ "description": "Shortcut: true generates favicon.ico (default size: 64), false disables it."
72
69
  },
73
- "size": {
74
- "type": "integer",
75
- "minimum": 1,
76
- "default": 64,
77
- "description": "Size of the embedded PNG in the .ico file (default: 64)."
70
+ {
71
+ "type": "object",
72
+ "description": "Generate a favicon.ico file from this asset.",
73
+ "required": ["required"],
74
+ "properties": {
75
+ "required": {
76
+ "type": "boolean",
77
+ "description": "Whether to generate the .ico file."
78
+ },
79
+ "size": {
80
+ "type": "integer",
81
+ "minimum": 1,
82
+ "default": 64,
83
+ "description": "Size of the embedded PNG in the .ico file (default: 64)."
84
+ }
85
+ }
78
86
  }
79
- }
87
+ ]
80
88
  }
81
89
  }
82
90
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-asset",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Config-driven image asset generator. Resize, convert, and generate favicons from a single JSON config.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/config.js CHANGED
@@ -50,6 +50,29 @@ export async function loadConfig(configPath) {
50
50
  if (!Array.isArray(asset.sizes) || asset.sizes.length === 0) {
51
51
  throw new Error(`Asset "${asset.name}" must have a non-empty "sizes" array.`);
52
52
  }
53
+
54
+ if (asset.ico !== undefined) {
55
+ const isBooleanIco = typeof asset.ico === "boolean";
56
+ const isObjectIco = typeof asset.ico === "object" && asset.ico !== null && !Array.isArray(asset.ico);
57
+
58
+ if (!isBooleanIco && !isObjectIco) {
59
+ throw new Error(`Asset "${asset.name}" has invalid "ico". Use boolean or object.`);
60
+ }
61
+
62
+ if (isObjectIco && asset.ico.size !== undefined) {
63
+ if (!Number.isInteger(asset.ico.size) || asset.ico.size < 1) {
64
+ throw new Error(`Asset "${asset.name}" has invalid "ico.size". Use a positive integer.`);
65
+ }
66
+ }
67
+
68
+ if (isObjectIco && asset.ico.required === undefined) {
69
+ throw new Error(`Asset "${asset.name}" must include "ico.required" when "ico" is an object.`);
70
+ }
71
+
72
+ if (isObjectIco && typeof asset.ico.required !== "boolean") {
73
+ throw new Error(`Asset "${asset.name}" has invalid "ico.required". Use true or false.`);
74
+ }
75
+ }
53
76
  }
54
77
 
55
78
  return config;
@@ -74,17 +97,13 @@ export function defaultConfig() {
74
97
  source: "favicon.svg",
75
98
  sizes: [16, 32, 48],
76
99
  destination: "public/icons",
77
- ico: {
78
- required: true,
79
- size: 96,
80
- },
100
+ ico: true,
81
101
  },
82
102
  {
83
103
  name: "opengraph-image",
84
104
  source: "icon.svg",
85
105
  sizes: ["1200x630"],
86
- destination: "public/icons",
87
- format: "jpeg",
106
+ destination: "public",
88
107
  },
89
108
  ],
90
109
  };
package/src/generate.js CHANGED
@@ -5,6 +5,24 @@ import { parseSize, buildFileName, generateImage, generateIco } from "./image.js
5
5
  import { cleanGeneratedFiles } from "./clean.js";
6
6
  import * as log from "./log.js";
7
7
 
8
+ function resolveIcoConfig(ico) {
9
+ if (ico === true) {
10
+ return { enabled: true, size: 64 };
11
+ }
12
+
13
+ if (ico === false || ico == null) {
14
+ return { enabled: false, size: 64 };
15
+ }
16
+
17
+ if (typeof ico === "object") {
18
+ const enabled = ico.required === true;
19
+ const size = typeof ico.size === "number" ? ico.size : 64;
20
+ return { enabled, size };
21
+ }
22
+
23
+ return { enabled: false, size: 64 };
24
+ }
25
+
8
26
  export async function generate(cwd, configFlag) {
9
27
  const configPath = resolveConfigPath(cwd, configFlag);
10
28
 
@@ -43,11 +61,12 @@ export async function generate(cwd, configFlag) {
43
61
  totalFiles++;
44
62
  }
45
63
 
46
- if (asset.ico?.required) {
64
+ const ico = resolveIcoConfig(asset.ico);
65
+ if (ico.enabled) {
47
66
  const icoPath = path.join(destinationDir, "favicon.ico");
48
- await generateIco(sourcePath, icoPath, asset.ico.size || 64);
67
+ await generateIco(sourcePath, icoPath, ico.size);
49
68
 
50
- log.success("favicon.ico", `${asset.ico.size || 64}×${asset.ico.size || 64}`);
69
+ log.success("favicon.ico", `${ico.size}×${ico.size}`);
51
70
  totalFiles++;
52
71
  }
53
72
  }