@octaviaflow/icon-build-helpers 1.0.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/README.md +50 -0
- package/package.json +55 -0
- package/src/builders/index.js +33 -0
- package/src/builders/plugins/virtual.js +51 -0
- package/src/builders/react/builder.js +313 -0
- package/src/builders/react/components/CarbonIcon.d.ts +18 -0
- package/src/builders/react/components/Icon.tsx +87 -0
- package/src/builders/react/next/babel.js +37 -0
- package/src/builders/react/next/convert.js +107 -0
- package/src/builders/react/next/templates.js +71 -0
- package/src/builders/react/next/typescript.js +87 -0
- package/src/builders/react/next.js +382 -0
- package/src/builders/svg.js +28 -0
- package/src/builders/vanilla.js +115 -0
- package/src/index.js +21 -0
- package/src/metadata/README.md +37 -0
- package/src/metadata/adapters/index.js +34 -0
- package/src/metadata/adapters/memory.js +55 -0
- package/src/metadata/adapters/yml.js +92 -0
- package/src/metadata/extension.js +92 -0
- package/src/metadata/extensions/assets.js +45 -0
- package/src/metadata/extensions/categories.js +141 -0
- package/src/metadata/extensions/deprecated.js +73 -0
- package/src/metadata/extensions/icons.js +152 -0
- package/src/metadata/extensions/index.js +48 -0
- package/src/metadata/extensions/module-info.js +154 -0
- package/src/metadata/extensions/module-name.js +54 -0
- package/src/metadata/extensions/output/getModuleName.js +52 -0
- package/src/metadata/extensions/output/index.js +251 -0
- package/src/metadata/extensions/output/optimizer.js +226 -0
- package/src/metadata/extensions/pictograms.js +85 -0
- package/src/metadata/index.js +178 -0
- package/src/metadata/migrations/2020-01-27.js +78 -0
- package/src/metadata/migrations/2020-02-17-remove-usage-fields.js +45 -0
- package/src/metadata/migrations/2020-02-17-update-pictogram-files.js +79 -0
- package/src/metadata/migrations/README.md +12 -0
- package/src/metadata/storage.js +68 -0
- package/src/metadata/validate.js +54 -0
- package/src/registry.js +158 -0
- package/src/tools.js +18 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright OctaviaFlow
|
|
3
|
+
* Author: Vishal Kumar
|
|
4
|
+
* Created: 11/November/2025
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { babel } = require("@rollup/plugin-babel");
|
|
11
|
+
const path = require("path");
|
|
12
|
+
const { rollup } = require("rollup");
|
|
13
|
+
const virtual = require("./plugins/virtual");
|
|
14
|
+
|
|
15
|
+
const BANNER = `/**
|
|
16
|
+
* Copyright IBM Corp. 2016, 2023
|
|
17
|
+
*
|
|
18
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
19
|
+
* LICENSE file in the root directory of this source tree.
|
|
20
|
+
*
|
|
21
|
+
* Code generated by @octaviaflow/icon-build-helpers. DO NOT EDIT.
|
|
22
|
+
*/`;
|
|
23
|
+
|
|
24
|
+
const babelConfig = {
|
|
25
|
+
babelrc: false,
|
|
26
|
+
exclude: /node_modules/,
|
|
27
|
+
presets: [
|
|
28
|
+
[
|
|
29
|
+
"@babel/preset-env",
|
|
30
|
+
{
|
|
31
|
+
targets: {
|
|
32
|
+
browsers: ["extends browserslist-config-octaviaflow"],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
],
|
|
37
|
+
babelHelpers: "bundled",
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
async function builder(metadata, { output }) {
|
|
41
|
+
const modules = metadata.icons.flatMap((icon) => {
|
|
42
|
+
return icon.output.map((size) => {
|
|
43
|
+
const source = `export default ${JSON.stringify(size.descriptor)};`;
|
|
44
|
+
return {
|
|
45
|
+
source,
|
|
46
|
+
filepath: size.filepath,
|
|
47
|
+
moduleName: size.moduleName,
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const files = {
|
|
53
|
+
"index.js": `${BANNER}\n\n`,
|
|
54
|
+
};
|
|
55
|
+
const input = {
|
|
56
|
+
"index.js": "index.js",
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
for (const m of modules) {
|
|
60
|
+
files[m.filepath] = m.source;
|
|
61
|
+
input[m.filepath] = m.filepath;
|
|
62
|
+
files["index.js"] +=
|
|
63
|
+
`\nexport { default as ${m.moduleName} } from '${m.filepath}';`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const bundle = await rollup({
|
|
67
|
+
input,
|
|
68
|
+
plugins: [virtual(files), babel(babelConfig)],
|
|
69
|
+
onwarn: (warning, warn) => {
|
|
70
|
+
// Suppress warnings for large number of files
|
|
71
|
+
if (warning.code === "CIRCULAR_DEPENDENCY") return;
|
|
72
|
+
warn(warning);
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const bundles = [
|
|
77
|
+
{
|
|
78
|
+
directory: path.join(output, "es"),
|
|
79
|
+
format: "esm",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
directory: path.join(output, "lib"),
|
|
83
|
+
format: "commonjs",
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
for (const { directory, format } of bundles) {
|
|
88
|
+
const outputOptions = {
|
|
89
|
+
dir: directory,
|
|
90
|
+
format,
|
|
91
|
+
entryFileNames: "[name]",
|
|
92
|
+
banner: BANNER,
|
|
93
|
+
exports: "auto",
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
await bundle.write(outputOptions);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const umd = await rollup({
|
|
100
|
+
input: "index.js",
|
|
101
|
+
plugins: [virtual(files), babel(babelConfig)],
|
|
102
|
+
onwarn: (warning, warn) => {
|
|
103
|
+
if (warning.code === "CIRCULAR_DEPENDENCY") return;
|
|
104
|
+
warn(warning);
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
await umd.write({
|
|
109
|
+
file: path.join(output, "umd/index.js"),
|
|
110
|
+
format: "umd",
|
|
111
|
+
name: "OctaviaFlowIcons",
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = builder;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright OctaviaFlow
|
|
3
|
+
* Author: Vishal Kumar
|
|
4
|
+
* Created: 11/November/2025
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
const builders = require('./builders');
|
|
14
|
+
const Metadata = require('./metadata');
|
|
15
|
+
const Registry = require('./registry');
|
|
16
|
+
|
|
17
|
+
module.exports = {
|
|
18
|
+
builders,
|
|
19
|
+
Metadata,
|
|
20
|
+
Registry,
|
|
21
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Metadata
|
|
2
|
+
|
|
3
|
+
## About
|
|
4
|
+
|
|
5
|
+
We store metadata for a collection of SVG assets to help with searching and
|
|
6
|
+
using icons in the Carbon Design System. However, due to the large number of
|
|
7
|
+
assets we maintain, we needed to build a system for organizing information about
|
|
8
|
+
these icons and creating an output file to be consumed by tooling.
|
|
9
|
+
|
|
10
|
+
As a result, the Metadata module provides support for building, scaffolding, and
|
|
11
|
+
verifying metadata information about a collection of SVG assets. Under the hood,
|
|
12
|
+
this module will build up a registry of all available assets and compare them
|
|
13
|
+
against metadata files called "extensions". These files are typically written in
|
|
14
|
+
YAML and are separated to make authoring of specific types of data easier.
|
|
15
|
+
|
|
16
|
+
In general, we support the following extension types:
|
|
17
|
+
|
|
18
|
+
- Icons: provides information for icons available from the source directory of
|
|
19
|
+
SVG assets
|
|
20
|
+
- Categories: provides category and subcategory information for a collection of
|
|
21
|
+
icons
|
|
22
|
+
- Module name: provides computed names used in code for an icon
|
|
23
|
+
- Deprecations: provides a listing of icons that have been deprecated and
|
|
24
|
+
details how to update usage to the preferred format
|
|
25
|
+
|
|
26
|
+
To support the above use-cases, Metadata makes use of the following concepts:
|
|
27
|
+
|
|
28
|
+
- [Registry](./registry.js): build up a source of truth for all available SVG
|
|
29
|
+
assets in a source tree
|
|
30
|
+
- [Extensions](./extensions/index.js): distinct sources of metadata captured for
|
|
31
|
+
icons. These modules provide support for verifying file structure, extending
|
|
32
|
+
the resulting output metadata, and logical checks to verify information
|
|
33
|
+
present (or not present) in these files
|
|
34
|
+
- [Adapters](./adapters.js): provide support for authoring metadata in a variety
|
|
35
|
+
of formats, we currently author in YAML
|
|
36
|
+
- [Storage](./storage.js): ability to read and write extension files for a given
|
|
37
|
+
adapter
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright OctaviaFlow
|
|
3
|
+
* Author: Vishal Kumar
|
|
4
|
+
* Created: 11/November/2025
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Copyright IBM Corp. 2020, 2023
|
|
12
|
+
*
|
|
13
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
14
|
+
* LICENSE file in the root directory of this source tree.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
const memory = require('./memory');
|
|
20
|
+
const yml = require('./yml');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* An adapter defines how we work with a specific file format and defines the
|
|
24
|
+
* operations for reading and writing files of that type for a particular
|
|
25
|
+
* location
|
|
26
|
+
* @typedef {object} Adapter
|
|
27
|
+
* @property {Function} read
|
|
28
|
+
* @property {Function} write
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
module.exports = {
|
|
32
|
+
memory,
|
|
33
|
+
yml,
|
|
34
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright OctaviaFlow
|
|
3
|
+
* Author: Vishal Kumar
|
|
4
|
+
* Created: 11/November/2025
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Copyright IBM Corp. 2020, 2023
|
|
12
|
+
*
|
|
13
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
14
|
+
* LICENSE file in the root directory of this source tree.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
const filesystem = new Map();
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {string} directory
|
|
25
|
+
* @param {string} name
|
|
26
|
+
* @returns {Promise<any>}
|
|
27
|
+
*/
|
|
28
|
+
async function read(directory, name) {
|
|
29
|
+
const filepath = path.join(directory, path.format({ name }));
|
|
30
|
+
|
|
31
|
+
if (filesystem.has(filepath)) {
|
|
32
|
+
return filesystem.get(filepath);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Unable to find extension \`${name}\` at filepath: ${filepath}`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {string} directory
|
|
42
|
+
* @param {string} name
|
|
43
|
+
* @param {any} data
|
|
44
|
+
* @returns {Promise<void>}
|
|
45
|
+
*/
|
|
46
|
+
async function write(directory, name, data) {
|
|
47
|
+
const filepath = path.join(directory, path.format({ name }));
|
|
48
|
+
filesystem.set(filepath, data);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = {
|
|
52
|
+
read,
|
|
53
|
+
write,
|
|
54
|
+
filesystem,
|
|
55
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright OctaviaFlow
|
|
3
|
+
* Author: Vishal Kumar
|
|
4
|
+
* Created: 11/November/2025
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Copyright IBM Corp. 2020, 2023
|
|
12
|
+
*
|
|
13
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
14
|
+
* LICENSE file in the root directory of this source tree.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
const fs = require('fs-extra');
|
|
20
|
+
const yaml = require('js-yaml');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get the filename for a given path basename. This is helpful to
|
|
25
|
+
* figure out which file we need to load in from the filesystem for the given
|
|
26
|
+
* adapter.
|
|
27
|
+
* @param {string} name
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
function getFilenameFor(name) {
|
|
31
|
+
return path.format({
|
|
32
|
+
name,
|
|
33
|
+
ext: '.yml',
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Serialize the given data to a YML format
|
|
39
|
+
* @param {object} data
|
|
40
|
+
* @returns {string}
|
|
41
|
+
*/
|
|
42
|
+
function serialize(data) {
|
|
43
|
+
return yaml.safeDump(data);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Deserialize the given YML data to JavaScript
|
|
48
|
+
* @param {object} data
|
|
49
|
+
* @returns {string}
|
|
50
|
+
*/
|
|
51
|
+
function deserialize(data) {
|
|
52
|
+
return yaml.safeLoad(data);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @param {string} directory
|
|
57
|
+
* @param {string} name
|
|
58
|
+
* @returns {Promise<any>}
|
|
59
|
+
*/
|
|
60
|
+
async function read(directory, name) {
|
|
61
|
+
const filepath = path.join(directory, getFilenameFor(name));
|
|
62
|
+
|
|
63
|
+
if (!(await fs.pathExists(filepath))) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Unable to find extension \`${name}\` at filepath: ` +
|
|
66
|
+
`${filepath}. Either create the file or update the extension ` +
|
|
67
|
+
`to be computed.`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return deserialize(await fs.readFile(filepath, 'utf8'));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @param {string} directory
|
|
76
|
+
* @param {string} name
|
|
77
|
+
* @param {any} data
|
|
78
|
+
* @returns {Promise<void>}
|
|
79
|
+
*/
|
|
80
|
+
async function write(directory, name, data) {
|
|
81
|
+
const filepath = path.join(directory, getFilenameFor(name));
|
|
82
|
+
|
|
83
|
+
await fs.ensureFile(filepath);
|
|
84
|
+
await fs.writeFile(filepath, serialize(data), 'utf8');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = {
|
|
88
|
+
serialize,
|
|
89
|
+
deserialize,
|
|
90
|
+
read,
|
|
91
|
+
write,
|
|
92
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright OctaviaFlow
|
|
3
|
+
* Author: Vishal Kumar
|
|
4
|
+
* Created: 11/November/2025
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Copyright IBM Corp. 2020, 2023
|
|
12
|
+
*
|
|
13
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
14
|
+
* LICENSE file in the root directory of this source tree.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {object} Extension
|
|
21
|
+
* @property {string} name - the name of the extension
|
|
22
|
+
* @property {JoiSchema} [schema] - a schema that validates the structure of
|
|
23
|
+
* the file for an extension
|
|
24
|
+
* @property {Function} [extend] - add information for the extension to the
|
|
25
|
+
* output metadata structure
|
|
26
|
+
* @property {Function} [validate] - validate that the data available in the
|
|
27
|
+
* registry matches the data received for the extension
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @typedef {Function} ExtensionBuilder
|
|
32
|
+
* @param {object} config
|
|
33
|
+
* @returns {Extension}
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {Extension} extension
|
|
38
|
+
* @returns {void}
|
|
39
|
+
*/
|
|
40
|
+
function validate(extension) {
|
|
41
|
+
if (!extension.name) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
`Expected extension to have a name, instead received: \`${extension.name}\``
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {(ExtensionBuilder | [Extension, object])} builderOrOptions
|
|
50
|
+
* @returns {Extension}
|
|
51
|
+
*/
|
|
52
|
+
function loadExtension(builderOrOptions) {
|
|
53
|
+
if (Array.isArray(builderOrOptions)) {
|
|
54
|
+
const [builder, options] = builderOrOptions;
|
|
55
|
+
const extension = builder(options);
|
|
56
|
+
validate(extension);
|
|
57
|
+
return extension;
|
|
58
|
+
}
|
|
59
|
+
const extension = builderOrOptions();
|
|
60
|
+
validate(extension);
|
|
61
|
+
return extension;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @param {Array<ExtensionBuilder | [Extension, object]>} [builderOrOptions]
|
|
66
|
+
* @returns {Array<Extension>}
|
|
67
|
+
*/
|
|
68
|
+
function load(builderOrOptions = []) {
|
|
69
|
+
const extensions = builderOrOptions.map(loadExtension);
|
|
70
|
+
const runOrder = [];
|
|
71
|
+
|
|
72
|
+
function order(extension) {
|
|
73
|
+
const match = runOrder.find((entry) => entry.name === extension.name);
|
|
74
|
+
if (match) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (Array.isArray(extension.before)) {
|
|
79
|
+
extension.before.map(loadExtension).forEach(order);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
runOrder.push(extension);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
extensions.forEach(order);
|
|
86
|
+
|
|
87
|
+
return runOrder;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
module.exports = {
|
|
91
|
+
load,
|
|
92
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright OctaviaFlow
|
|
3
|
+
* Author: Vishal Kumar
|
|
4
|
+
* Created: 11/November/2025
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Copyright IBM Corp. 2020, 2023
|
|
12
|
+
*
|
|
13
|
+
* This assets code is licensed under the Apache-2.0 license found in the
|
|
14
|
+
* LICENSE file in the root directory of this assets tree.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
const fs = require('fs-extra');
|
|
20
|
+
const path = require('path');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Provide source and filepath asset information for a given icon
|
|
24
|
+
* @type {Extension}
|
|
25
|
+
*/
|
|
26
|
+
const assets = () => {
|
|
27
|
+
return {
|
|
28
|
+
name: 'assets',
|
|
29
|
+
computed: true,
|
|
30
|
+
extend(metadata, _data, registry, { input }) {
|
|
31
|
+
for (const entry of metadata.icons) {
|
|
32
|
+
const icon = registry.get(entry.name);
|
|
33
|
+
entry.assets = icon.assets.map(({ size, filepath }) => {
|
|
34
|
+
return {
|
|
35
|
+
size,
|
|
36
|
+
filepath: path.relative(input.svg, filepath),
|
|
37
|
+
source: fs.readFileSync(filepath, 'utf8'),
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
module.exports = assets;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright OctaviaFlow
|
|
3
|
+
* Author: Vishal Kumar
|
|
4
|
+
* Created: 11/November/2025
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Copyright IBM Corp. 2020, 2023
|
|
12
|
+
*
|
|
13
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
14
|
+
* LICENSE file in the root directory of this source tree.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
const Joi = require('@hapi/joi');
|
|
20
|
+
|
|
21
|
+
// Supports both top-level categories and subcategories
|
|
22
|
+
//
|
|
23
|
+
// categories:
|
|
24
|
+
// - name: Category name
|
|
25
|
+
// members:
|
|
26
|
+
// - Member 1
|
|
27
|
+
// - Member 2
|
|
28
|
+
//
|
|
29
|
+
// categories:
|
|
30
|
+
// - name: Category name
|
|
31
|
+
// subcategories:
|
|
32
|
+
// - name: Subcategory name
|
|
33
|
+
// members:
|
|
34
|
+
// - Member 1
|
|
35
|
+
// - Member 2
|
|
36
|
+
const categories = () => {
|
|
37
|
+
return {
|
|
38
|
+
name: 'categories',
|
|
39
|
+
|
|
40
|
+
schema: Joi.object().keys({
|
|
41
|
+
categories: Joi.array()
|
|
42
|
+
.items(
|
|
43
|
+
Joi.object().keys({
|
|
44
|
+
name: Joi.string().required(),
|
|
45
|
+
members: Joi.array().items(Joi.string()),
|
|
46
|
+
subcategories: Joi.array().items(
|
|
47
|
+
Joi.object().keys({
|
|
48
|
+
name: Joi.string().required(),
|
|
49
|
+
members: Joi.array().items(Joi.string()).required(),
|
|
50
|
+
})
|
|
51
|
+
),
|
|
52
|
+
})
|
|
53
|
+
)
|
|
54
|
+
.required(),
|
|
55
|
+
}),
|
|
56
|
+
|
|
57
|
+
extend(metadata, data) {
|
|
58
|
+
const { categories } = data;
|
|
59
|
+
|
|
60
|
+
metadata.categories = categories;
|
|
61
|
+
|
|
62
|
+
for (const category of categories) {
|
|
63
|
+
const { name, members, subcategories } = category;
|
|
64
|
+
|
|
65
|
+
if (Array.isArray(subcategories)) {
|
|
66
|
+
for (const subcategory of subcategories) {
|
|
67
|
+
for (const member of subcategory.members) {
|
|
68
|
+
const icon = metadata.icons.find(({ name }) => name === member);
|
|
69
|
+
icon.category = name;
|
|
70
|
+
icon.subcategory = subcategory.name;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
for (const member of members) {
|
|
77
|
+
const icon = metadata.icons.find(({ name }) => name === member);
|
|
78
|
+
icon.category = name;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
validate(registry, data) {
|
|
84
|
+
// Flatten the category data into a flat list of members with corresponding
|
|
85
|
+
// name and category data
|
|
86
|
+
const members = [];
|
|
87
|
+
|
|
88
|
+
for (const category of data.categories) {
|
|
89
|
+
if (Array.isArray(category.subcategories)) {
|
|
90
|
+
for (const subcategory of category.subcategories) {
|
|
91
|
+
for (const member of subcategory.members) {
|
|
92
|
+
members.push({
|
|
93
|
+
name: member,
|
|
94
|
+
category: category.name,
|
|
95
|
+
subcategory: subcategory.name,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
for (const member of category.members) {
|
|
103
|
+
members.push({
|
|
104
|
+
name: member,
|
|
105
|
+
category: category.name,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Verify that every asset in the registry has category information
|
|
111
|
+
for (const icon of registry.values()) {
|
|
112
|
+
const match = members.find((member) => member.name === icon.id);
|
|
113
|
+
if (!match) {
|
|
114
|
+
const filepaths = icon.assets.map((asset) => asset.filepath);
|
|
115
|
+
throw new Error(
|
|
116
|
+
`Expected the following icon to have category information: ` +
|
|
117
|
+
`\`${icon.id}\`. This icon has assets in the following locations:\n` +
|
|
118
|
+
filepaths.join('\n')
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Verify that every asset with a category exists in the registry
|
|
124
|
+
for (const member of members) {
|
|
125
|
+
if (!registry.has(member.name)) {
|
|
126
|
+
let categoryPath = `category \`${member.category}\``;
|
|
127
|
+
if (member.subcategory) {
|
|
128
|
+
categoryPath += `, subcategory \`${member.subcategory}\``;
|
|
129
|
+
}
|
|
130
|
+
throw new Error(
|
|
131
|
+
`Found the entry \`${member.name}\` in ${categoryPath} that does ` +
|
|
132
|
+
`not have a corresponding icon or asset. Either this icon does ` +
|
|
133
|
+
`not exist, or is not available in the current directory.`
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
module.exports = categories;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright OctaviaFlow
|
|
3
|
+
* Author: Vishal Kumar
|
|
4
|
+
* Created: 11/November/2025
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Copyright IBM Corp. 2020, 2023
|
|
12
|
+
*
|
|
13
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
14
|
+
* LICENSE file in the root directory of this source tree.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
const Joi = require('@hapi/joi');
|
|
20
|
+
|
|
21
|
+
// Supports a list of deprecated assets
|
|
22
|
+
//
|
|
23
|
+
// deprecated:
|
|
24
|
+
// - name: asset-name-1
|
|
25
|
+
// - name: asset-name-2
|
|
26
|
+
//
|
|
27
|
+
// In the future, we may want to include a reason for the deprecation, or a
|
|
28
|
+
// notice for what icon to use instead.
|
|
29
|
+
const deprecated = () => {
|
|
30
|
+
return {
|
|
31
|
+
name: 'deprecated',
|
|
32
|
+
|
|
33
|
+
schema: Joi.object().keys({
|
|
34
|
+
deprecated: Joi.array()
|
|
35
|
+
.items(
|
|
36
|
+
Joi.object().keys({
|
|
37
|
+
name: Joi.string().required(),
|
|
38
|
+
reason: Joi.string(),
|
|
39
|
+
})
|
|
40
|
+
)
|
|
41
|
+
.required(),
|
|
42
|
+
}),
|
|
43
|
+
|
|
44
|
+
extend(metadata, data) {
|
|
45
|
+
const { deprecated } = data;
|
|
46
|
+
|
|
47
|
+
for (const icon of metadata.icons) {
|
|
48
|
+
const entry = deprecated.find(({ name }) => name === icon.name);
|
|
49
|
+
if (entry) {
|
|
50
|
+
icon.deprecated = true;
|
|
51
|
+
if (entry.reason) {
|
|
52
|
+
icon.reason = entry.reason;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
validate(registry, data) {
|
|
59
|
+
for (const icon of data.deprecated) {
|
|
60
|
+
const entry = registry.has(icon.name);
|
|
61
|
+
if (!entry) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Expected the deprecated icon \`${icon.name}\` to exist. Either ` +
|
|
64
|
+
`this icon does not exist, or is not available in the given SVG ` +
|
|
65
|
+
`directory`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
module.exports = deprecated;
|