@oroinc/oro-webpack-config-builder 6.1.0-lts06 → 6.1.0-lts08
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/error-handler.js +9 -1
- package/js-to-scss/create-font-list.js +58 -0
- package/js-to-scss/index.js +5 -0
- package/modules-config/modules-config-loader.js +14 -3
- package/oro-webpack-config.js +66 -44
- package/package.json +2 -3
- package/utils.js +1 -15
- package/validation/errors/theme-scheme-error.js +36 -0
- package/validation/index.js +5 -0
- package/validation/schemas/svg-icons-schema-full.js +1 -1
- package/validation/schemas/theme-schema-full.js +11 -0
- package/validation/schemas/theme-schema.js +83 -0
- package/validation/svg-icons-validator.js +3 -3
- package/validation/theme-validator.js +53 -0
- package/plugin/css-to-json/index.js +0 -66
- package/plugin/css-to-json/json-transformer.js +0 -42
package/error-handler.js
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
const BaseError = require('./validation/errors/base-error');
|
|
2
|
-
const {isVerboseMode
|
|
2
|
+
const {isVerboseMode} = require('./utils');
|
|
3
3
|
const {red, yellow, green, bgRed} = require('colorette');
|
|
4
4
|
|
|
5
|
+
const emptyLine = length => new Array(length).fill(' ').join('');
|
|
6
|
+
const multiline = (color, msg) => {
|
|
7
|
+
msg = ` ${msg}`;
|
|
8
|
+
msg = msg + emptyLine(120 - msg.length);
|
|
9
|
+
|
|
10
|
+
return `\n${color(emptyLine(msg.length))}\n${color(msg)}\n${color(emptyLine(msg.length))}`;
|
|
11
|
+
};
|
|
12
|
+
|
|
5
13
|
class ErrorHandler {
|
|
6
14
|
constructor() {
|
|
7
15
|
this.failedThemes = [];
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts JS object to SCSS list variable for theme fonts
|
|
3
|
+
* @example {
|
|
4
|
+
* main: {
|
|
5
|
+
* family: 'Jakarta',
|
|
6
|
+
* variants: [{
|
|
7
|
+
* path: '/font.woff2',
|
|
8
|
+
* style: 'normal',
|
|
9
|
+
* weight: '700'
|
|
10
|
+
* }]
|
|
11
|
+
* formats: ['woff2']
|
|
12
|
+
* }
|
|
13
|
+
* } => (
|
|
14
|
+
* 'main': (
|
|
15
|
+
* 'family': 'Jakarta',
|
|
16
|
+
* 'variants': (
|
|
17
|
+
* (
|
|
18
|
+
* 'path': '/font.woff2',
|
|
19
|
+
* 'style': 'normal',
|
|
20
|
+
* 'weight': '700',
|
|
21
|
+
* )
|
|
22
|
+
* )
|
|
23
|
+
* 'formats': ('woff2')
|
|
24
|
+
* )
|
|
25
|
+
* )
|
|
26
|
+
*
|
|
27
|
+
* @param {object} fonts
|
|
28
|
+
* @param {string }scssVarName
|
|
29
|
+
* @returns {string}
|
|
30
|
+
*/
|
|
31
|
+
const fontObjToSCSS = ({fonts, scssVarName = 'global-theme-fonts'} = {}) => {
|
|
32
|
+
if (!Object.keys(fonts).length) {
|
|
33
|
+
return `$${scssVarName}: ()`;
|
|
34
|
+
}
|
|
35
|
+
const fontsVariantsVars = Object.entries(fonts).map(([name, font]) => {
|
|
36
|
+
return `
|
|
37
|
+
'${name}': (
|
|
38
|
+
'family': '${font.family}',
|
|
39
|
+
'variants': (
|
|
40
|
+
${font.variants.map(item => `(
|
|
41
|
+
'path': '${item.path}',
|
|
42
|
+
${item.weight !== void 0 ? `'weight': ${item.weight},` : ''}
|
|
43
|
+
${item.style !== void 0 ? `'style': ${item.style}` : ''}
|
|
44
|
+
)`).join(`, `)}
|
|
45
|
+
),
|
|
46
|
+
'formats': (${font.formats.map(format => `'${format}'`).join(', ')})
|
|
47
|
+
)
|
|
48
|
+
`;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return `
|
|
52
|
+
$${scssVarName}: (
|
|
53
|
+
${fontsVariantsVars.join(`, `)}
|
|
54
|
+
);
|
|
55
|
+
`;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
module.exports = fontObjToSCSS;
|
|
@@ -71,6 +71,8 @@ class ModulesConfigLoader {
|
|
|
71
71
|
* @private
|
|
72
72
|
*/
|
|
73
73
|
_collectThemes(themes, themesLocation, themeInfoFileName) {
|
|
74
|
+
this._processedFiles = [];
|
|
75
|
+
|
|
74
76
|
this._bundles.forEach(bundle => {
|
|
75
77
|
const source = bundle + themesLocation;
|
|
76
78
|
|
|
@@ -81,11 +83,20 @@ class ModulesConfigLoader {
|
|
|
81
83
|
if (!fs.lstatSync(themePath).isDirectory()) {
|
|
82
84
|
return;
|
|
83
85
|
}
|
|
86
|
+
|
|
84
87
|
const themeFile = path.resolve(themePath, themeInfoFileName);
|
|
85
|
-
if (!fs.existsSync(themeFile)) return;
|
|
86
88
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
if (!fs.existsSync(themeFile)) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this._processedFiles.push(themeFile);
|
|
94
|
+
|
|
95
|
+
const doc = yaml.load(fs.readFileSync(themeFile, 'utf8'));
|
|
96
|
+
|
|
97
|
+
validation.checkSchema(themeFile, doc, name);
|
|
98
|
+
|
|
99
|
+
themes[name] = merge(themes[name] || {}, doc, {arrayMerge});
|
|
89
100
|
});
|
|
90
101
|
});
|
|
91
102
|
}
|
package/oro-webpack-config.js
CHANGED
|
@@ -19,7 +19,6 @@ const ThemeConfigFactory = require('./theme-config-factory');
|
|
|
19
19
|
const path = require('path');
|
|
20
20
|
const fs = require('fs');
|
|
21
21
|
const prepareModulesMap = require('./plugin/map/prepare-modules-map');
|
|
22
|
-
const CssToJsonPlugin = require('./plugin/css-to-json');
|
|
23
22
|
const resolve = require('enhanced-resolve');
|
|
24
23
|
const {merge: webpackMerge} = require('webpack-merge');
|
|
25
24
|
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
|
@@ -29,8 +28,10 @@ const EventEmitter = require('events');
|
|
|
29
28
|
const ErrorHandler = require('./error-handler');
|
|
30
29
|
const SVGSprite = require('./svg-sprite');
|
|
31
30
|
const TerserPlugin = require('terser-webpack-plugin');
|
|
31
|
+
const jsToSCSS = require('./js-to-scss');
|
|
32
32
|
require('resolve-url-loader');
|
|
33
33
|
require('lezer-loader');
|
|
34
|
+
|
|
34
35
|
class ConfigBuilder {
|
|
35
36
|
constructor() {
|
|
36
37
|
this._projectPath = '';
|
|
@@ -274,6 +275,7 @@ class ConfigBuilder {
|
|
|
274
275
|
|
|
275
276
|
const webpackConfig = {
|
|
276
277
|
watchOptions: {
|
|
278
|
+
followSymlinks: true,
|
|
277
279
|
aggregateTimeout: 200,
|
|
278
280
|
ignored: /[\/\\]node_modules[\/\\].*\.js$/
|
|
279
281
|
},
|
|
@@ -319,44 +321,6 @@ class ConfigBuilder {
|
|
|
319
321
|
/[\/\\]bundles[\/\\]\.*[\/\\]lib[\/\\](?!chaplin|bootstrap|jquery\.dialog).*\.js$/
|
|
320
322
|
],
|
|
321
323
|
rules: [
|
|
322
|
-
{
|
|
323
|
-
test: /\.s?css$/,
|
|
324
|
-
use: [{
|
|
325
|
-
loader: args.hot ? 'style-loader' : MiniCssExtractPlugin.loader
|
|
326
|
-
}, {
|
|
327
|
-
loader: 'css-loader',
|
|
328
|
-
options: {
|
|
329
|
-
importLoaders: 1,
|
|
330
|
-
sourceMap: true,
|
|
331
|
-
// can't use esModule since resolve-url-loader needs file path to start with '~'
|
|
332
|
-
esModule: false
|
|
333
|
-
}
|
|
334
|
-
}, {
|
|
335
|
-
loader: 'resolve-url-loader'
|
|
336
|
-
}, {
|
|
337
|
-
loader: 'postcss-loader',
|
|
338
|
-
options: {
|
|
339
|
-
sourceMap: true,
|
|
340
|
-
postcssOptions: {
|
|
341
|
-
plugins: [
|
|
342
|
-
require('autoprefixer')
|
|
343
|
-
]
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}, {
|
|
347
|
-
loader: 'sass-loader',
|
|
348
|
-
options: {
|
|
349
|
-
implementation: require('sass'),
|
|
350
|
-
sassOptions: {
|
|
351
|
-
includePaths: [
|
|
352
|
-
path.join(this.resolvedPublicPath, '/bundles')
|
|
353
|
-
],
|
|
354
|
-
outputStyle: 'expanded'
|
|
355
|
-
},
|
|
356
|
-
sourceMap: true
|
|
357
|
-
}
|
|
358
|
-
}]
|
|
359
|
-
},
|
|
360
324
|
{
|
|
361
325
|
test: /\.(eot|ttf|woff|woff2|cur|ico|svg|png|jpg|gif)$/,
|
|
362
326
|
loader: 'url-loader',
|
|
@@ -502,7 +466,10 @@ class ConfigBuilder {
|
|
|
502
466
|
);
|
|
503
467
|
}
|
|
504
468
|
}
|
|
505
|
-
let {
|
|
469
|
+
let {
|
|
470
|
+
rtl_support: rtlSupport = false,
|
|
471
|
+
resolve_extra_paths: resolveExtraPaths = []
|
|
472
|
+
} = themeDefinition;
|
|
506
473
|
const resolvedBuildPath = path.join(this.resolvedPublicPath, buildPublicPath);
|
|
507
474
|
|
|
508
475
|
if (resolveExtraPaths.length) {
|
|
@@ -534,10 +501,6 @@ class ConfigBuilder {
|
|
|
534
501
|
}));
|
|
535
502
|
}
|
|
536
503
|
|
|
537
|
-
if (!skipCSS) {
|
|
538
|
-
plugins.push(new CssToJsonPlugin());
|
|
539
|
-
}
|
|
540
|
-
|
|
541
504
|
const cssEntryPoints = !skipCSS ? this._getCssEntryPoints(buildName, buildPublicPath) : {};
|
|
542
505
|
const jsEntryPoints = !skipJS ? jsBuildConfig.entry : {};
|
|
543
506
|
|
|
@@ -563,6 +526,45 @@ class ConfigBuilder {
|
|
|
563
526
|
plugins,
|
|
564
527
|
module: {
|
|
565
528
|
rules: [
|
|
529
|
+
{
|
|
530
|
+
test: /\.s?css$/,
|
|
531
|
+
use: [{
|
|
532
|
+
loader: args.hot ? 'style-loader' : MiniCssExtractPlugin.loader
|
|
533
|
+
}, {
|
|
534
|
+
loader: 'css-loader',
|
|
535
|
+
options: {
|
|
536
|
+
importLoaders: 1,
|
|
537
|
+
sourceMap: true,
|
|
538
|
+
// can't use esModule since resolve-url-loader needs file path to start with '~'
|
|
539
|
+
esModule: false
|
|
540
|
+
}
|
|
541
|
+
}, {
|
|
542
|
+
loader: 'resolve-url-loader'
|
|
543
|
+
}, {
|
|
544
|
+
loader: 'postcss-loader',
|
|
545
|
+
options: {
|
|
546
|
+
sourceMap: true,
|
|
547
|
+
postcssOptions: {
|
|
548
|
+
plugins: [
|
|
549
|
+
require('autoprefixer')
|
|
550
|
+
]
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}, {
|
|
554
|
+
loader: 'sass-loader',
|
|
555
|
+
options: {
|
|
556
|
+
implementation: require('sass'),
|
|
557
|
+
sassOptions: {
|
|
558
|
+
includePaths: [
|
|
559
|
+
path.join(this.resolvedPublicPath, '/bundles')
|
|
560
|
+
],
|
|
561
|
+
outputStyle: 'expanded'
|
|
562
|
+
},
|
|
563
|
+
sourceMap: true,
|
|
564
|
+
additionalData: this.prepareAdditionalSCSS.bind(this, themeDefinition)
|
|
565
|
+
}
|
|
566
|
+
}]
|
|
567
|
+
},
|
|
566
568
|
{
|
|
567
569
|
test: /[\/\\]configs\.json$/,
|
|
568
570
|
loader: 'config-loader',
|
|
@@ -577,6 +579,18 @@ class ConfigBuilder {
|
|
|
577
579
|
};
|
|
578
580
|
}
|
|
579
581
|
|
|
582
|
+
prepareAdditionalSCSS(theme, content, loaderContext) {
|
|
583
|
+
if (typeof theme.fonts === 'object') {
|
|
584
|
+
const fonts = {};
|
|
585
|
+
for (const [name, {family, formats, variants}] of Object.entries(theme.fonts)) {
|
|
586
|
+
fonts[name] = {family, formats, variants};
|
|
587
|
+
}
|
|
588
|
+
return jsToSCSS.createFontList({fonts}) + content;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
return content;
|
|
592
|
+
}
|
|
593
|
+
|
|
580
594
|
_initialize(args, env) {
|
|
581
595
|
const entryPointFileWriter = new EntryPointFileWriter(this._publicPath);
|
|
582
596
|
|
|
@@ -608,6 +622,14 @@ class ConfigBuilder {
|
|
|
608
622
|
this.resolvedProjectPath,
|
|
609
623
|
this._publicPath
|
|
610
624
|
);
|
|
625
|
+
|
|
626
|
+
for (const [theme, config] of Object.entries(this._layoutModulesConfigLoader.themes)) {
|
|
627
|
+
validation.themeValidator.checkFullSchema(
|
|
628
|
+
config,
|
|
629
|
+
this._layoutModulesConfigLoader.processedFiles,
|
|
630
|
+
theme
|
|
631
|
+
);
|
|
632
|
+
}
|
|
611
633
|
this._layoutStyleLoader = new LayoutStyleLoader(this._layoutModulesConfigLoader, entryPointFileWriter);
|
|
612
634
|
this._layoutThemeConfigFactory = new ThemeConfigFactory(
|
|
613
635
|
this._layoutModulesConfigLoader,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oroinc/oro-webpack-config-builder",
|
|
3
|
-
"version": "6.1.0-
|
|
3
|
+
"version": "6.1.0-lts08",
|
|
4
4
|
"author": "Oro, Inc. (https://oroinc.com)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "An integration of OroPlatform based applications with the Webpack.",
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
"css-loader": "^6.8.1",
|
|
17
17
|
"css-minimizer-webpack-plugin": "~5.0.0",
|
|
18
18
|
"deepmerge": "~4.3.1",
|
|
19
|
-
"esbuild-loader": "^4.3.0",
|
|
20
19
|
"exports-loader": "~4.0.0",
|
|
21
20
|
"expose-loader": "~4.1.0",
|
|
21
|
+
"esbuild-loader": "^4.3.0",
|
|
22
22
|
"file-loader": "~6.2.0",
|
|
23
23
|
"html-webpack-plugin": "~5.5.0",
|
|
24
24
|
"imports-loader": "~4.0.1",
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
"path": "0.12.7",
|
|
31
31
|
"postcss": "<8.4.33",
|
|
32
32
|
"postcss-loader": "~7.3.4",
|
|
33
|
-
"postcss-safe-parser": "^7.0.1",
|
|
34
33
|
"printf": "~0.6.0",
|
|
35
34
|
"resolve-url-loader": "^5.0.0",
|
|
36
35
|
"rtlcss-webpack-plugin": "~4.0.6",
|
package/utils.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
let prodMode;
|
|
2
2
|
let verboseMode;
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
module.exports = {
|
|
5
5
|
isVerboseMode() {
|
|
6
6
|
if (verboseMode === void 0) {
|
|
7
7
|
verboseMode = process.argv.filter(arg => {
|
|
@@ -13,7 +13,6 @@ const utils = {
|
|
|
13
13
|
|
|
14
14
|
return verboseMode;
|
|
15
15
|
},
|
|
16
|
-
|
|
17
16
|
isProdMode() {
|
|
18
17
|
if (prodMode !== void 0) {
|
|
19
18
|
return prodMode;
|
|
@@ -27,18 +26,5 @@ const utils = {
|
|
|
27
26
|
});
|
|
28
27
|
|
|
29
28
|
return prodMode;
|
|
30
|
-
},
|
|
31
|
-
|
|
32
|
-
emptyLine(length) {
|
|
33
|
-
return new Array(length).fill(' ').join('');
|
|
34
|
-
},
|
|
35
|
-
|
|
36
|
-
multiline(color, msg) {
|
|
37
|
-
msg = ` ${msg}`;
|
|
38
|
-
msg = msg + utils.emptyLine(120 - msg.length);
|
|
39
|
-
|
|
40
|
-
return `\n${color(utils.emptyLine(msg.length))}\n${color(msg)}\n${color(utils.emptyLine(msg.length))}`;
|
|
41
29
|
}
|
|
42
30
|
};
|
|
43
|
-
|
|
44
|
-
module.exports = utils;
|
|
@@ -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 "theme.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 Theme config';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = SvgIconsSchemaError;
|
package/validation/index.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
const assetsValidation = require('./assets-validator');
|
|
2
2
|
const jsmodulesValidator = require('./jsmodules-validator');
|
|
3
3
|
const svgIconsValidator = require('./svg-icons-validator');
|
|
4
|
+
const themeValidator = require('./theme-validator');
|
|
4
5
|
|
|
5
6
|
const isJSModulesPath = path => /jsmodules([-a-zA-Z\d]*)\.yml$/.test(path);
|
|
6
7
|
const isAssetsPath = path => /assets\.yml$/.test(path);
|
|
7
8
|
const isSvgIconsPath = path => /svg-icons\.yml$/.test(path);
|
|
9
|
+
const isThemePath = path => /theme\.yml$/.test(path);
|
|
8
10
|
|
|
9
11
|
module.exports = {
|
|
10
12
|
assetsValidation,
|
|
11
13
|
jsmodulesValidator,
|
|
12
14
|
svgIconsValidator,
|
|
15
|
+
themeValidator,
|
|
13
16
|
|
|
14
17
|
/**
|
|
15
18
|
* set public path for all validators
|
|
@@ -36,6 +39,8 @@ module.exports = {
|
|
|
36
39
|
}
|
|
37
40
|
} else if (isSvgIconsPath(filePath)) {
|
|
38
41
|
svgIconsValidator.checkSchema(filePath, doc, theme);
|
|
42
|
+
} else if (isThemePath(filePath)) {
|
|
43
|
+
themeValidator.checkSchema(filePath, doc, theme);
|
|
39
44
|
}
|
|
40
45
|
}
|
|
41
46
|
};
|
|
@@ -10,7 +10,7 @@ module.exports = {
|
|
|
10
10
|
type: 'object',
|
|
11
11
|
properties: {
|
|
12
12
|
exclude: {
|
|
13
|
-
description: 'The "exclude" property is an array of
|
|
13
|
+
description: 'The "exclude" property is an array of svg files to exclude from svg sprite.',
|
|
14
14
|
type: 'array',
|
|
15
15
|
minItems: 0
|
|
16
16
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema to validate theme.yml files
|
|
3
|
+
*
|
|
4
|
+
* @description
|
|
5
|
+
* Full scheme complements "theme-schema" one.
|
|
6
|
+
* It should have only rules which are not defined in "theme-schema" schema due to avoid duplicates in error messages
|
|
7
|
+
*/
|
|
8
|
+
module.exports = {
|
|
9
|
+
type: 'object',
|
|
10
|
+
required: ['label']
|
|
11
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema to validate theme.yml files
|
|
3
|
+
*/
|
|
4
|
+
module.exports = {
|
|
5
|
+
type: 'object',
|
|
6
|
+
properties: {
|
|
7
|
+
label: {
|
|
8
|
+
type: 'string'
|
|
9
|
+
},
|
|
10
|
+
description: {
|
|
11
|
+
type: 'string'
|
|
12
|
+
},
|
|
13
|
+
groups: {
|
|
14
|
+
type: 'array',
|
|
15
|
+
items: {
|
|
16
|
+
type: 'string'
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
icon: {
|
|
20
|
+
type: 'string'
|
|
21
|
+
},
|
|
22
|
+
logo: {
|
|
23
|
+
type: 'string'
|
|
24
|
+
},
|
|
25
|
+
logo_small: {
|
|
26
|
+
type: 'string'
|
|
27
|
+
},
|
|
28
|
+
rtl_support: {
|
|
29
|
+
type: 'boolean'
|
|
30
|
+
},
|
|
31
|
+
svg_icons_support: {
|
|
32
|
+
type: 'boolean'
|
|
33
|
+
},
|
|
34
|
+
fonts: {
|
|
35
|
+
type: 'object',
|
|
36
|
+
patternProperties: {
|
|
37
|
+
'.*': {
|
|
38
|
+
type: 'object',
|
|
39
|
+
required: ['family', 'variants', 'formats'],
|
|
40
|
+
additionalProperties: false,
|
|
41
|
+
properties: {
|
|
42
|
+
family: {
|
|
43
|
+
type: 'string'
|
|
44
|
+
},
|
|
45
|
+
variants: {
|
|
46
|
+
type: 'array',
|
|
47
|
+
items: {
|
|
48
|
+
type: 'object',
|
|
49
|
+
required: ['path'],
|
|
50
|
+
additionalProperties: false,
|
|
51
|
+
properties: {
|
|
52
|
+
path: {
|
|
53
|
+
type: 'string'
|
|
54
|
+
},
|
|
55
|
+
weight: {
|
|
56
|
+
anyOf: [{
|
|
57
|
+
type: 'string'
|
|
58
|
+
}, {
|
|
59
|
+
type: 'integer'
|
|
60
|
+
}]
|
|
61
|
+
},
|
|
62
|
+
style: {
|
|
63
|
+
type: 'string'
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
formats: {
|
|
69
|
+
type: 'array',
|
|
70
|
+
items: {
|
|
71
|
+
type: 'string'
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
preload: {
|
|
75
|
+
type: 'boolean'
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
@@ -4,7 +4,7 @@ const schemaValidator = require('./schema-validator');
|
|
|
4
4
|
const {isProdMode} = require('../utils');
|
|
5
5
|
const EventEmitter = require('events');
|
|
6
6
|
const emitter = new EventEmitter();
|
|
7
|
-
const
|
|
7
|
+
const SvgIconsSchemaError = require('./errors/svg-icons-schema-error');
|
|
8
8
|
|
|
9
9
|
module.exports = Object.assign({}, schemaValidator, {
|
|
10
10
|
emitter,
|
|
@@ -22,7 +22,7 @@ module.exports = Object.assign({}, schemaValidator, {
|
|
|
22
22
|
const result = this.validateSchema(schema, doc);
|
|
23
23
|
|
|
24
24
|
if (!result.valid) {
|
|
25
|
-
const error = new
|
|
25
|
+
const error = new SvgIconsSchemaError(result.formattedError, [filePath], theme);
|
|
26
26
|
|
|
27
27
|
this.emitter.emit('error', error);
|
|
28
28
|
}
|
|
@@ -43,7 +43,7 @@ module.exports = Object.assign({}, schemaValidator, {
|
|
|
43
43
|
const result = this.validateSchema(fullSchema, doc);
|
|
44
44
|
|
|
45
45
|
if (!result.valid) {
|
|
46
|
-
const error = new
|
|
46
|
+
const error = new SvgIconsSchemaError(result.formattedError, files, theme);
|
|
47
47
|
|
|
48
48
|
this.emitter.emit('error', error);
|
|
49
49
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const schema = require('./schemas/theme-schema');
|
|
2
|
+
const fullSchema = require('./schemas/theme-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 ThemeSchemaError = require('./errors/theme-scheme-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 ThemeSchemaError(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 ThemeSchemaError(result.formattedError, files, theme);
|
|
47
|
+
|
|
48
|
+
this.emitter.emit('error', error);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return result.valid;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const webpack = require('webpack');
|
|
3
|
-
const jsonTransform = require('./json-transformer');
|
|
4
|
-
const {multiline} = require('./../../utils');
|
|
5
|
-
const {bgRed} = require('colorette');
|
|
6
|
-
|
|
7
|
-
const isExportCssFile = filename => {
|
|
8
|
-
return path.extname(filename) === '.css' && /_json(\.rtl)?$/.test(path.basename(filename, '.css'));
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
class CssToJsonPlugin {
|
|
12
|
-
constructor(options) {}
|
|
13
|
-
|
|
14
|
-
processAssets = (compilation, callback) => {
|
|
15
|
-
const chunks = Array.from(compilation.chunks);
|
|
16
|
-
|
|
17
|
-
chunks.forEach(chunk => {
|
|
18
|
-
const files = Array.from(chunk.files);
|
|
19
|
-
|
|
20
|
-
files.filter(isExportCssFile).forEach(filename => {
|
|
21
|
-
const src = compilation.assets[filename].source();
|
|
22
|
-
const json = jsonTransform(src);
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
JSON.parse(json);
|
|
26
|
-
} catch (e) {
|
|
27
|
-
console.error(
|
|
28
|
-
multiline(bgRed, `[ERROR] The JSON generated from the CSS file "${filename}" is invalid.`)
|
|
29
|
-
);
|
|
30
|
-
console.error(e.message);
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
let jsonFileName = '[name].json';
|
|
35
|
-
|
|
36
|
-
if (filename.includes('rtl')) {
|
|
37
|
-
jsonFileName = '[name].rtl.json';
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const dstFileName = compilation.getPath(jsonFileName, {
|
|
41
|
-
chunk,
|
|
42
|
-
cssFileName: filename
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
compilation.assets[dstFileName] = new webpack.sources.RawSource(json);
|
|
46
|
-
chunk.files.add(dstFileName);
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
callback();
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
apply(compiler) {
|
|
54
|
-
compiler.hooks.compilation.tap('CssToJsonPlugin', compilation => {
|
|
55
|
-
compilation.hooks.processAssets.tapAsync(
|
|
56
|
-
{
|
|
57
|
-
name: 'CssToJsonPlugin',
|
|
58
|
-
stage: compilation.PROCESS_ASSETS_STAGE_OPTIMIZE
|
|
59
|
-
},
|
|
60
|
-
(chunks, callback) => this.processAssets(compilation, callback)
|
|
61
|
-
);
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
module.exports = CssToJsonPlugin;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
const postcss = require('postcss');
|
|
2
|
-
const safeParser = require('postcss-safe-parser');
|
|
3
|
-
|
|
4
|
-
const normalizeSelector = selector => {
|
|
5
|
-
return selector
|
|
6
|
-
.replace(/^\./g, '')
|
|
7
|
-
.replace(/:(\w+)/, (matched, group) => {
|
|
8
|
-
return group.charAt(0).toUpperCase() + group.slice(1);
|
|
9
|
-
})
|
|
10
|
-
/*
|
|
11
|
-
* #main > .item => _main__item
|
|
12
|
-
* input[type="text"] => input_type_text
|
|
13
|
-
* .button + .icon => button__icon
|
|
14
|
-
* .p:has(.btn) => p_has__btn_
|
|
15
|
-
*/
|
|
16
|
-
.replace(/[:\.\[\]\(\)#\s>+~]/g, '_');
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const transform = src => {
|
|
20
|
-
const classMap = {};
|
|
21
|
-
const root = postcss.parse(src, {parser: safeParser});
|
|
22
|
-
root.walkRules(rule => {
|
|
23
|
-
const selector = rule.selector;
|
|
24
|
-
|
|
25
|
-
if (!selector.startsWith('.')) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const normalizedKey = normalizeSelector(selector);
|
|
30
|
-
const props = [];
|
|
31
|
-
rule.walkDecls(decl => {
|
|
32
|
-
const important = decl.important ? ' !important' : '';
|
|
33
|
-
props.push(`${decl.prop}: ${decl.value}${important}`);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
classMap[normalizedKey] = props.join('; ') + (props.length ? ';' : '');
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
return JSON.stringify(classMap, null, 2);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
module.exports = transform;
|