@oroinc/oro-webpack-config-builder 5.1.0-dev0011 → 5.1.0-dev0013
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/modules-config/layout-modules-config-loader.js +23 -0
- package/modules-config/modules-config-loader.js +31 -0
- package/oro-webpack-config.js +21 -27
- package/package.json +5 -3
- package/svg-sprite/index.js +135 -0
- package/svg-sprite/svg-sprite-config.js +5 -0
- package/svg-sprite/svgo-config.js +32 -0
- package/validation/errors/svg-icons-schema-error.js +36 -0
- package/validation/index.js +5 -0
- package/validation/schemas/svg-icons-schema-full.js +18 -0
- package/validation/schemas/svg-icons-schema.js +17 -0
- package/validation/svg-icons-validator.js +53 -0
|
@@ -22,6 +22,29 @@ class LayoutModulesConfigLoader extends ModulesConfigLoader {
|
|
|
22
22
|
return themeConfig;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* @param {string} theme Theme name
|
|
27
|
+
* @param {string} dirPath path to the directory were to search
|
|
28
|
+
* @param {string} fileExtName file extension
|
|
29
|
+
* @return {Object} Merged Configs loaded from all the bundles Yaml files matched by dirPath
|
|
30
|
+
*/
|
|
31
|
+
getFilesPaths(theme, dirPath = '/public', fileExtName = '.txt') {
|
|
32
|
+
let iconsPaths = super.getFilesPaths(theme, dirPath, fileExtName);
|
|
33
|
+
|
|
34
|
+
// recursive process parent theme
|
|
35
|
+
const {parent: parentTheme} = this.themes[theme];
|
|
36
|
+
if (typeof parentTheme === 'string') {
|
|
37
|
+
const processedFiles = this.processedFiles;
|
|
38
|
+
const parentIconsPaths = this.getFilesPaths(parentTheme, dirPath, fileExtName);
|
|
39
|
+
|
|
40
|
+
iconsPaths = [...iconsPaths, ...parentIconsPaths];
|
|
41
|
+
// processedFiles from parent theme is added to processedFiles of current theme
|
|
42
|
+
this._processedFiles = [...processedFiles, ...this.processedFiles];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return iconsPaths;
|
|
46
|
+
}
|
|
47
|
+
|
|
25
48
|
/**
|
|
26
49
|
* All build names:
|
|
27
50
|
* - based on theme names
|
|
@@ -119,6 +119,37 @@ class ModulesConfigLoader {
|
|
|
119
119
|
|
|
120
120
|
return configs;
|
|
121
121
|
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @param {string} theme Theme name
|
|
125
|
+
* @param {string} dirPath path to the directory were to search
|
|
126
|
+
* @param {string} fileExtName file extension
|
|
127
|
+
* @return {Object} Merged Configs loaded from all the bundles Yaml files matched by dirPath
|
|
128
|
+
*/
|
|
129
|
+
getFilesPaths(theme, dirPath = '/public', fileExtName = '.txt') {
|
|
130
|
+
const result = [];
|
|
131
|
+
|
|
132
|
+
this._processedFiles = [];
|
|
133
|
+
this._bundles.forEach(bundle => {
|
|
134
|
+
const absolutePath = path.resolve(bundle, dirPath, `${theme}/svg-icons`);
|
|
135
|
+
|
|
136
|
+
if (fs.existsSync(absolutePath)) {
|
|
137
|
+
this._processedFiles.push(absolutePath);
|
|
138
|
+
|
|
139
|
+
const files = fs.readdirSync(absolutePath);
|
|
140
|
+
|
|
141
|
+
for (const file of files) {
|
|
142
|
+
const fileExt = path.extname(file);
|
|
143
|
+
|
|
144
|
+
if (fileExt === fileExtName) {
|
|
145
|
+
result.push(`${absolutePath}/${file}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
122
153
|
}
|
|
123
154
|
|
|
124
155
|
module.exports = ModulesConfigLoader;
|
package/oro-webpack-config.js
CHANGED
|
@@ -26,9 +26,7 @@ const RtlCssWebpackPlugin = require('rtlcss-webpack-plugin');
|
|
|
26
26
|
const validation = require('./validation');
|
|
27
27
|
const EventEmitter = require('events');
|
|
28
28
|
const ErrorHandler = require('./error-handler');
|
|
29
|
-
|
|
30
|
-
const {ModifySourcePlugin, ConcatOperation} = require('modify-source-webpack-plugin');
|
|
31
|
-
|
|
29
|
+
const SVGSprite = require('./svg-sprite');
|
|
32
30
|
require('resolve-url-loader');
|
|
33
31
|
|
|
34
32
|
class ConfigBuilder {
|
|
@@ -189,7 +187,7 @@ class ConfigBuilder {
|
|
|
189
187
|
}
|
|
190
188
|
|
|
191
189
|
get resolvedProjectPath() {
|
|
192
|
-
if (this._resolvedProjectPath
|
|
190
|
+
if (this._resolvedProjectPath === undefined) {
|
|
193
191
|
this._resolvedProjectPath = path.resolve(this._projectPath);
|
|
194
192
|
}
|
|
195
193
|
return this._resolvedProjectPath;
|
|
@@ -333,7 +331,7 @@ class ConfigBuilder {
|
|
|
333
331
|
}, {
|
|
334
332
|
loader: 'sass-loader',
|
|
335
333
|
options: {
|
|
336
|
-
implementation: require(
|
|
334
|
+
implementation: require('sass'),
|
|
337
335
|
sassOptions: {
|
|
338
336
|
includePaths: [
|
|
339
337
|
path.join(this.resolvedPublicPath, '/bundles')
|
|
@@ -354,6 +352,10 @@ class ConfigBuilder {
|
|
|
354
352
|
publicPath: '../../_static/',
|
|
355
353
|
name: this._getVersionedPath('[path][name].[ext]', this.assetVersion)
|
|
356
354
|
}
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
test: /\.grammar$/,
|
|
358
|
+
use: 'lezer-loader',
|
|
357
359
|
}
|
|
358
360
|
]
|
|
359
361
|
},
|
|
@@ -373,20 +375,7 @@ class ConfigBuilder {
|
|
|
373
375
|
}),
|
|
374
376
|
new AfterWebpackLogsPlugin(
|
|
375
377
|
stats => this.emitter.emit('build:complete', stats)
|
|
376
|
-
)
|
|
377
|
-
new ModifySourcePlugin({
|
|
378
|
-
rules: [
|
|
379
|
-
{
|
|
380
|
-
test: /\.js$/,
|
|
381
|
-
operations: [
|
|
382
|
-
new ConcatOperation(
|
|
383
|
-
'end',
|
|
384
|
-
'\n;console.log("$FILE_PATH".replace("node_modules", "\x1B[92;4mnode_modules\x1B[m").replace("orothemedefault51", "\x1B[94;4morothemedefault51\x1B[m"));\n'
|
|
385
|
-
)
|
|
386
|
-
]
|
|
387
|
-
}
|
|
388
|
-
]
|
|
389
|
-
}),
|
|
378
|
+
)
|
|
390
379
|
]
|
|
391
380
|
};
|
|
392
381
|
|
|
@@ -440,7 +429,7 @@ class ConfigBuilder {
|
|
|
440
429
|
}
|
|
441
430
|
|
|
442
431
|
_getThemeWebpackConfig(buildName, args, env) {
|
|
443
|
-
let {skipCSS, skipJS, skipRTL} = env;
|
|
432
|
+
let {skipCSS, skipJS, skipRTL, skipSVG} = env;
|
|
444
433
|
let themeDefinition;
|
|
445
434
|
let jsBuildConfig;
|
|
446
435
|
let buildPublicPath;
|
|
@@ -454,7 +443,8 @@ class ConfigBuilder {
|
|
|
454
443
|
'Resources/config/jsmodules.yml',
|
|
455
444
|
'config/oro/jsmodules.yml'
|
|
456
445
|
]
|
|
457
|
-
);
|
|
446
|
+
);
|
|
447
|
+
validation.jsmodulesValidator.checkFullSchema(
|
|
458
448
|
jsModulesConfig,
|
|
459
449
|
this._themeConfigFactory?._configLoader.processedFiles,
|
|
460
450
|
buildName
|
|
@@ -484,19 +474,23 @@ class ConfigBuilder {
|
|
|
484
474
|
buildName
|
|
485
475
|
);
|
|
486
476
|
jsBuildConfig = this._layoutThemeConfigFactory.create(buildPublicPath, jsModulesConfig);
|
|
487
|
-
}
|
|
488
|
-
let {rtl_support: rtlSupport = false, resolveExtraPaths = []} = themeDefinition;
|
|
489
|
-
const resolvedBuildPath = path.join(this.resolvedPublicPath, buildPublicPath);
|
|
490
477
|
|
|
491
|
-
|
|
492
|
-
|
|
478
|
+
if (!skipSVG) {
|
|
479
|
+
new SVGSprite(
|
|
480
|
+
this._layoutModulesConfigLoader,
|
|
481
|
+
buildName,
|
|
482
|
+
this._publicPath,
|
|
483
|
+
buildPublicPath
|
|
484
|
+
);
|
|
485
|
+
}
|
|
493
486
|
}
|
|
487
|
+
const {rtl_support: rtlSupport = false} = themeDefinition;
|
|
488
|
+
const resolvedBuildPath = path.join(this.resolvedPublicPath, buildPublicPath);
|
|
494
489
|
|
|
495
490
|
const resolverConfig = {
|
|
496
491
|
modules: [
|
|
497
492
|
resolvedBuildPath,
|
|
498
493
|
this.resolvedPublicPath,
|
|
499
|
-
...resolveExtraPaths,
|
|
500
494
|
path.join(this.resolvedProjectPath, '/assets'),
|
|
501
495
|
path.join(this.resolvedPublicPath, '/bundles'),
|
|
502
496
|
path.join(this.resolvedPublicPath, '/js'),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oroinc/oro-webpack-config-builder",
|
|
3
|
-
"version": "5.1.0-
|
|
3
|
+
"version": "5.1.0-dev0013",
|
|
4
4
|
"author": "Oro, Inc (https://www.oroinc.com)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "An integration of OroPlatform based applications with the Webpack.",
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"html-webpack-plugin": "~5.5.0",
|
|
22
22
|
"imports-loader": "~4.0.1",
|
|
23
23
|
"js-yaml": "~4.1.0",
|
|
24
|
+
"lezer-loader": "^0.3.0",
|
|
24
25
|
"mini-css-extract-plugin": "~2.7.1",
|
|
25
26
|
"minimist": "~1.2.7",
|
|
26
|
-
"modify-source-webpack-plugin": "^4.1.0",
|
|
27
27
|
"nan": "~2.17.0",
|
|
28
28
|
"path": "0.12.7",
|
|
29
29
|
"postcss": "~8.4.23",
|
|
@@ -35,11 +35,13 @@
|
|
|
35
35
|
"sass-loader": "~13.2.0",
|
|
36
36
|
"schema-utils": "^4.0.0",
|
|
37
37
|
"style-loader": "~3.3.1",
|
|
38
|
+
"svgo": "^3.0.2",
|
|
39
|
+
"svgstore": "^3.0.1",
|
|
38
40
|
"terser": "~5.17.1",
|
|
39
41
|
"text-loader": "0.0.1",
|
|
40
42
|
"underscore": "1.13.*",
|
|
41
43
|
"url-loader": "~4.1.1",
|
|
42
|
-
"webpack": "
|
|
44
|
+
"webpack": "~5.80.0",
|
|
43
45
|
"webpack-bundle-analyzer": "~4.8.0",
|
|
44
46
|
"webpack-cli": "~5.0.0",
|
|
45
47
|
"webpack-dev-server": "^4.11.1",
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const {svgIconsValidator} = require('../validation');
|
|
4
|
+
const svgoConfig = require('./svgo-config');
|
|
5
|
+
const svgSpriteConfig = require('./svg-sprite-config');
|
|
6
|
+
const {optimize} = require('svgo');
|
|
7
|
+
const svgstore = require('svgstore');
|
|
8
|
+
class SvgSprite {
|
|
9
|
+
/**
|
|
10
|
+
* @param {ModulesConfigLoader} configLoader
|
|
11
|
+
* @param {string} theme
|
|
12
|
+
* @param {string} publicPath
|
|
13
|
+
* @param {string} buildPublicPath
|
|
14
|
+
*/
|
|
15
|
+
constructor(configLoader, theme, publicPath, buildPublicPath) {
|
|
16
|
+
this.SPRITE_NAME = 'theme-icons';
|
|
17
|
+
this._configLoader = configLoader;
|
|
18
|
+
this._theme = theme;
|
|
19
|
+
this._publicPath = publicPath;
|
|
20
|
+
this._buildPublicPath = buildPublicPath;
|
|
21
|
+
|
|
22
|
+
this.optimize();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Starting optimization
|
|
27
|
+
*/
|
|
28
|
+
optimize() {
|
|
29
|
+
const svgConfig = this._configLoader.loadConfig(
|
|
30
|
+
this._theme,
|
|
31
|
+
'config/svg-icons.yml'
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
svgIconsValidator.checkFullSchema(svgConfig, this._configLoader.processedFiles, this._theme);
|
|
35
|
+
|
|
36
|
+
const svgPaths = this._configLoader.getFilesPaths(
|
|
37
|
+
this._theme,
|
|
38
|
+
'Resources/public/',
|
|
39
|
+
'.svg'
|
|
40
|
+
);
|
|
41
|
+
const exclude = svgConfig.exclude ?? [];
|
|
42
|
+
const filesToOptimize = [];
|
|
43
|
+
const filesNames = {};
|
|
44
|
+
|
|
45
|
+
svgPaths.forEach(icon => {
|
|
46
|
+
const svgName = path.parse(icon).name;
|
|
47
|
+
|
|
48
|
+
if (svgName === this.SPRITE_NAME) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
`The "${this.SPRITE_NAME}" is a reserved word and cannot be used as a svg name for building sprite.`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const toExclude = exclude.includes(svgName);
|
|
55
|
+
const fileIsChosenToMove = filesNames[svgName] === svgName;
|
|
56
|
+
|
|
57
|
+
if (toExclude === false && fileIsChosenToMove === false) {
|
|
58
|
+
filesToOptimize.push(icon);
|
|
59
|
+
filesNames[svgName] = svgName;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (filesToOptimize.length === 0) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
this.moveFiles(filesToOptimize);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Preparing files for optimization
|
|
72
|
+
* @param {Array} files
|
|
73
|
+
* @returns {Promise<void>}
|
|
74
|
+
*/
|
|
75
|
+
async moveFiles(files) {
|
|
76
|
+
const buildPath = path.join(this._buildPublicPath, 'svg-icons');
|
|
77
|
+
const dirPath = path.resolve(`${this._publicPath}${buildPath}`);
|
|
78
|
+
|
|
79
|
+
if (!fs.existsSync(dirPath)) {
|
|
80
|
+
fs.mkdirSync(dirPath, {recursive: true});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
fs.readdirSync(dirPath).forEach(file => {
|
|
85
|
+
fs.unlinkSync(path.join(dirPath, file));
|
|
86
|
+
});
|
|
87
|
+
} catch (error) {
|
|
88
|
+
throw new Error(error);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
await Promise.all(
|
|
92
|
+
files.map(file => this.optimizeFile(file, dirPath))
|
|
93
|
+
);
|
|
94
|
+
this.createSprite(fs.readdirSync(dirPath), dirPath);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Optimizing svg using svgo
|
|
99
|
+
* @param {Object} file
|
|
100
|
+
* @param {string} dirPath
|
|
101
|
+
* @returns {Promise<void>}
|
|
102
|
+
*/
|
|
103
|
+
async optimizeFile(file, dirPath) {
|
|
104
|
+
const {name, ext} = path.parse(file);
|
|
105
|
+
const filepath = path.join(dirPath, `${name}${ext}`);
|
|
106
|
+
|
|
107
|
+
const originalSvg = fs.readFileSync(file, 'utf8');
|
|
108
|
+
const {data: optimizedSvg} = await optimize(originalSvg, {
|
|
109
|
+
path: filepath,
|
|
110
|
+
...svgoConfig
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// svgo will always add a final newline when in pretty mode
|
|
114
|
+
const resultSvg = optimizedSvg.trim().replace(/(\n\r?|\r\n?)/g, '');
|
|
115
|
+
fs.writeFileSync(filepath, resultSvg, 'utf8');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Creating sprite
|
|
120
|
+
* @param {Array} files
|
|
121
|
+
* @param {string} dirPath
|
|
122
|
+
*/
|
|
123
|
+
createSprite(files, dirPath) {
|
|
124
|
+
const sprites = svgstore(svgSpriteConfig);
|
|
125
|
+
|
|
126
|
+
for (const file of files) {
|
|
127
|
+
const svgName = path.parse(file).name;
|
|
128
|
+
sprites.add(svgName, fs.readFileSync(path.join(dirPath, file), 'utf8'));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
fs.writeFileSync(path.join(dirPath, `${this.SPRITE_NAME}.svg`), sprites, 'utf8');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
module.exports = SvgSprite;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
multipass: true,
|
|
3
|
+
js2svg: {
|
|
4
|
+
pretty: true,
|
|
5
|
+
indent: 0,
|
|
6
|
+
eol: 'lf'
|
|
7
|
+
},
|
|
8
|
+
plugins: [{
|
|
9
|
+
name: 'preset-default',
|
|
10
|
+
params: {
|
|
11
|
+
overrides: {
|
|
12
|
+
removeUnknownsAndDefaults: {
|
|
13
|
+
keepRoleAttr: true
|
|
14
|
+
},
|
|
15
|
+
removeViewBox: false
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
// The next plugins are included in svgo but are not part of preset-default,
|
|
20
|
+
// so we need to enable them separately
|
|
21
|
+
'cleanupListOfValues',
|
|
22
|
+
{
|
|
23
|
+
name: 'removeAttrs',
|
|
24
|
+
params: {
|
|
25
|
+
attrs: [
|
|
26
|
+
'clip-rule',
|
|
27
|
+
'data-name',
|
|
28
|
+
'fill'
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
}]
|
|
32
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const BaseError = require('./base-error');
|
|
2
|
+
|
|
3
|
+
class SvgIconsSchemaError extends BaseError {
|
|
4
|
+
/**
|
|
5
|
+
* @example
|
|
6
|
+
* Invalid SVG config: the "svg-icons.yml" files in the "default" theme do not match the API schema.
|
|
7
|
+
* has an unknown property 'rest'.
|
|
8
|
+
* at default/config/svg-icons.yml
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* Invalid SVG config: the "svg-icons.yml" files in the "default" theme do not match the API schema.
|
|
12
|
+
* misses the property 'exclude'.
|
|
13
|
+
* List of processed files for the "default" theme:
|
|
14
|
+
* /default/config/svg-icons.yml
|
|
15
|
+
* /default/config/svg-icons.yml
|
|
16
|
+
*
|
|
17
|
+
* @param {string} reason
|
|
18
|
+
* @param {Array} files
|
|
19
|
+
* @param {string} theme
|
|
20
|
+
*/
|
|
21
|
+
constructor(reason, files, theme) {
|
|
22
|
+
let msg = `the "svg-icons.yml" files in the "${theme}" theme do not match the API schema.\n${reason}`;
|
|
23
|
+
|
|
24
|
+
const filesListMsg = BaseError.generateFilesListMsg(files, theme);
|
|
25
|
+
|
|
26
|
+
if (filesListMsg.length) {
|
|
27
|
+
msg = `${msg}\n${filesListMsg}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
super(msg);
|
|
31
|
+
|
|
32
|
+
this.name = 'Invalid SVG config';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = SvgIconsSchemaError;
|
package/validation/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
const assetsValidation = require('./assets-validator');
|
|
2
2
|
const jsmodulesValidator = require('./jsmodules-validator');
|
|
3
|
+
const svgIconsValidator = require('./svg-icons-validator');
|
|
3
4
|
|
|
4
5
|
const isJSModulesPath = path => /jsmodules([-a-zA-Z\d]*)\.yml$/.test(path);
|
|
5
6
|
const isAssetsPath = path => /assets\.yml$/.test(path);
|
|
7
|
+
const isSvgIconsPath = path => /svg-icons\.yml$/.test(path);
|
|
6
8
|
|
|
7
9
|
module.exports = {
|
|
8
10
|
assetsValidation,
|
|
9
11
|
jsmodulesValidator,
|
|
12
|
+
svgIconsValidator,
|
|
10
13
|
|
|
11
14
|
/**
|
|
12
15
|
* set public path for all validators
|
|
@@ -31,6 +34,8 @@ module.exports = {
|
|
|
31
34
|
if (validSchema) {
|
|
32
35
|
assetsValidation.checkInputsExist(filePath, doc, theme);
|
|
33
36
|
}
|
|
37
|
+
} else if (isSvgIconsPath(filePath)) {
|
|
38
|
+
svgIconsValidator.checkSchema(filePath, doc, theme);
|
|
34
39
|
}
|
|
35
40
|
}
|
|
36
41
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema to validate svg-icons.yml files
|
|
3
|
+
*
|
|
4
|
+
* @description
|
|
5
|
+
* Full scheme complements "svg-icons-schema" one.
|
|
6
|
+
* It should have only rules which are not defined in "svg-icons-schema" schema due to avoid duplicates in error messages
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
exclude: {
|
|
13
|
+
description: 'The "exclude" property is an array of svg files to exclude from svg sprite.',
|
|
14
|
+
type: 'array',
|
|
15
|
+
minItems: 0
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema to validate svg-icons.yml files
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
type: 'object',
|
|
7
|
+
properties: {
|
|
8
|
+
exclude: {
|
|
9
|
+
description: 'List of SVG files to exclude a from svg sprite.',
|
|
10
|
+
type: 'array',
|
|
11
|
+
items: {
|
|
12
|
+
type: 'string'
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
additionalProperties: false
|
|
17
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const schema = require('./schemas/svg-icons-schema');
|
|
2
|
+
const fullSchema = require('./schemas/svg-icons-schema-full');
|
|
3
|
+
const schemaValidator = require('./schema-validator');
|
|
4
|
+
const {isProdMode} = require('../utils');
|
|
5
|
+
const EventEmitter = require('events');
|
|
6
|
+
const emitter = new EventEmitter();
|
|
7
|
+
const SvgIsonsSchemaError = require('./errors/svg-icons-schema-error');
|
|
8
|
+
|
|
9
|
+
module.exports = Object.assign({}, schemaValidator, {
|
|
10
|
+
emitter,
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {string} filePath
|
|
14
|
+
* @param {Object} doc
|
|
15
|
+
* @param {string} theme
|
|
16
|
+
* @returns {boolean|undefined}
|
|
17
|
+
*/
|
|
18
|
+
checkSchema(filePath, doc, theme) {
|
|
19
|
+
if (isProdMode()) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const result = this.validateSchema(schema, doc);
|
|
23
|
+
|
|
24
|
+
if (!result.valid) {
|
|
25
|
+
const error = new SvgIsonsSchemaError(result.formattedError, [filePath], theme);
|
|
26
|
+
|
|
27
|
+
this.emitter.emit('error', error);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return result.valid;
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {Object} doc
|
|
35
|
+
* @param {Array} files
|
|
36
|
+
* @param {string} theme
|
|
37
|
+
* @returns {boolean|undefined}
|
|
38
|
+
*/
|
|
39
|
+
checkFullSchema(doc, files = [], theme) {
|
|
40
|
+
if (isProdMode()) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const result = this.validateSchema(fullSchema, doc);
|
|
44
|
+
|
|
45
|
+
if (!result.valid) {
|
|
46
|
+
const error = new SvgIsonsSchemaError(result.formattedError, files, theme);
|
|
47
|
+
|
|
48
|
+
this.emitter.emit('error', error);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return result.valid;
|
|
52
|
+
}
|
|
53
|
+
});
|