From 808bd0615b12bde89e319382e99eff8547df7f38 Mon Sep 17 00:00:00 2001 From: babich-a Date: Thu, 14 May 2020 15:52:05 +0300 Subject: [PATCH 1/7] Add linter to the scss themebuilder --- .eslintignore | 1 + docker-ci.sh | 3 + themebuilder-scss/.eslintignore | 5 + themebuilder-scss/.eslintrc | 18 + themebuilder-scss/package.json | 15 +- .../bootstrap-metadata/bootstrap-metadata.ts | 98 +- .../bootstrap-metadata/bootstrap4-metadata.ts | 86 +- .../migration-metadata/migration-metadata.ts | 236 ++-- themebuilder-scss/src/metadata/collector.ts | 96 +- themebuilder-scss/src/metadata/generate.ts | 25 +- themebuilder-scss/src/metadata/generator.ts | 127 +- .../src/modules/base-parameters.ts | 2 +- themebuilder-scss/src/modules/builder.ts | 24 +- .../src/modules/bundle-resolver.ts | 10 +- .../src/modules/clean-css-options.ts | 66 +- themebuilder-scss/src/modules/commands.ts | 6 +- .../src/modules/compile-manager.ts | 56 +- themebuilder-scss/src/modules/compiler.ts | 162 +-- .../src/modules/config-normalizer.ts | 261 ++-- .../src/modules/post-compiler.ts | 10 +- themebuilder-scss/src/modules/pre-compiler.ts | 11 +- themebuilder-scss/src/modules/themes.ts | 150 ++- themebuilder-scss/src/types/types.ts | 87 +- themebuilder-scss/tests/.eslintrc | 8 + .../compilation-results/no-changes-meta.ts | 40 +- themebuilder-scss/tests/data/metadata.ts | 18 +- .../tests/metadata/collector.test.ts | 173 ++- .../tests/metadata/generator.test.ts | 303 +++-- .../tests/modules/bundle-resolver.test.ts | 33 +- .../tests/modules/compile-manager.test.ts | 85 +- .../tests/modules/compiler-sass.test.ts | 149 +++ .../tests/modules/compiler.test.ts | 299 ++--- .../tests/modules/config-normalizer.test.ts | 1174 +++++++++-------- .../tests/modules/post-compiler.test.ts | 30 +- .../tests/modules/pre-compiler.test.ts | 9 +- themebuilder-scss/tsconfig.json | 5 +- 36 files changed, 2009 insertions(+), 1872 deletions(-) create mode 100644 themebuilder-scss/.eslintignore create mode 100644 themebuilder-scss/.eslintrc create mode 100644 themebuilder-scss/tests/.eslintrc create mode 100644 themebuilder-scss/tests/modules/compiler-sass.test.ts diff --git a/.eslintignore b/.eslintignore index a1a7449696c6..c7d8e8486646 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,3 +3,4 @@ js/viz/docs/* node_modules/* testing/helpers/sinon/* /themebuilder/data/metadata/* +/themebuilder-scss/* diff --git a/docker-ci.sh b/docker-ci.sh index 59ef8a076744..abba72be200b 100755 --- a/docker-ci.sh +++ b/docker-ci.sh @@ -193,6 +193,9 @@ function run_test_scss { npx gulp generate-scss npm run build-themes node build/gulp/scss/tests/identical.test.js + + cd themebuilder-scss + npm i && npm run test } function start_runner_watchdog { diff --git a/themebuilder-scss/.eslintignore b/themebuilder-scss/.eslintignore new file mode 100644 index 000000000000..331869f41286 --- /dev/null +++ b/themebuilder-scss/.eslintignore @@ -0,0 +1,5 @@ +coverage +dist +node_modules +src/data/metadata/* +jest.config.js \ No newline at end of file diff --git a/themebuilder-scss/.eslintrc b/themebuilder-scss/.eslintrc new file mode 100644 index 000000000000..97cf24b9972d --- /dev/null +++ b/themebuilder-scss/.eslintrc @@ -0,0 +1,18 @@ +{ + "env": { + "es6": true, + "node": true + }, + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint" + ], + "parserOptions": { + "project": "./tsconfig.json", + "ecmaVersion": 6, + "sourceType": "module" + }, + "extends": [ + "devextreme/typescript" + ] +} \ No newline at end of file diff --git a/themebuilder-scss/package.json b/themebuilder-scss/package.json index 4549f454542d..9a985076922a 100644 --- a/themebuilder-scss/package.json +++ b/themebuilder-scss/package.json @@ -19,7 +19,9 @@ "semver": "^5.6.0" }, "scripts": { - "test": "jest --coverage --verbose --detectOpenHandles", + "test-code": "jest --coverage --verbose --detectOpenHandles", + "lint": "eslint .", + "test": "npm run lint && npm run test-code", "clean-metadata": "", "generate-metadata": "ts-node --files=true src/metadata/generate.ts", "build-ts": "tsc", @@ -29,13 +31,20 @@ "@types/clean-css": "^4.2.1", "@types/jest": "^25.2.1", "@types/node-sass": "^4.11.0", - "eslint": "^6.8.0", + "@typescript-eslint/eslint-plugin": "^2.33.0", + "eslint": "^7.0.0", + "eslint-config-airbnb-typescript": "^7.2.1", + "eslint-config-devextreme": "^0.1.0", + "eslint-plugin-import": "^2.20.2", + "eslint-plugin-jest": "^23.11.0", + "eslint-plugin-jest-formatting": "^1.2.0", + "eslint-plugin-jsx-a11y": "^6.2.3", + "eslint-plugin-react": "^7.20.0", "express": "^4.16.4", "jest": "^25.4.0", "less": "3.9.0", "sinon": "^9.0.2", "ts-jest": "^25.5.0", - "ts-mock-imports": "^1.3.0", "ts-node": "^8.10.1", "typescript": "^3.8.3" } diff --git a/themebuilder-scss/src/data/bootstrap-metadata/bootstrap-metadata.ts b/themebuilder-scss/src/data/bootstrap-metadata/bootstrap-metadata.ts index 2860f4f47217..f9cad40a5dc4 100644 --- a/themebuilder-scss/src/data/bootstrap-metadata/bootstrap-metadata.ts +++ b/themebuilder-scss/src/data/bootstrap-metadata/bootstrap-metadata.ts @@ -1,66 +1,66 @@ export default { - 'base-font-family': '@font-family-sans-serif', - 'base-accent': '@brand-primary', - 'base-bg': '@body-bg', - 'base-text-color': '@text-color', - 'base-border-color': '@table-border-color', + 'base-font-family': '@font-family-sans-serif', + 'base-accent': '@brand-primary', + 'base-bg': '@body-bg', + 'base-text-color': '@text-color', + 'base-border-color': '@table-border-color', - 'base-border-radius': '@border-radius-base', - 'base-border-radius-large': '@border-radius-large', - 'base-border-radius-small': '@border-radius-small', + 'base-border-radius': '@border-radius-base', + 'base-border-radius-large': '@border-radius-large', + 'base-border-radius-small': '@border-radius-small', - 'base-success': '@brand-success', - 'base-warning': '@brand-warning', - 'base-danger': '@brand-danger', + 'base-success': '@brand-success', + 'base-warning': '@brand-warning', + 'base-danger': '@brand-danger', - 'base-link-color': '@link-color', - 'base-hover-color': '@table-bg-hover', + 'base-link-color': '@link-color', + 'base-hover-color': '@table-bg-hover', - 'button-normal-color': '@btn-default-color', - 'button-normal-bg': '@btn-default-bg', - 'button-normal-border-color': '@btn-default-border', + 'button-normal-color': '@btn-default-color', + 'button-normal-bg': '@btn-default-bg', + 'button-normal-border-color': '@btn-default-border', - 'button-default-color': '@btn-primary-color', - 'button-default-bg': '@btn-primary-bg', - 'button-default-border-color': '@btn-primary-border', + 'button-default-color': '@btn-primary-color', + 'button-default-bg': '@btn-primary-bg', + 'button-default-border-color': '@btn-primary-border', - 'button-success-color': '@btn-success-color', - 'button-success-bg': '@btn-success-bg', - 'button-success-border-color': '@btn-success-border', + 'button-success-color': '@btn-success-color', + 'button-success-bg': '@btn-success-bg', + 'button-success-border-color': '@btn-success-border', - 'button-danger-color': '@btn-danger-color', - 'button-danger-bg': '@btn-danger-bg', - 'button-danger-border-color': '@btn-danger-border', + 'button-danger-color': '@btn-danger-color', + 'button-danger-bg': '@btn-danger-bg', + 'button-danger-border-color': '@btn-danger-border', - 'button-border-radius': '@btn-border-radius-base', + 'button-border-radius': '@btn-border-radius-base', - 'texteditor-border-color': '@input-border', - 'texteditor-bg': '@input-bg', - 'texteditor-color': '@input-color', - 'texteditor-border-radius': '@input-border-radius', - 'texteditor-focused-border-color': '@input-border-focus', - 'texteditor-placeholder-color': '@input-color-placeholder', + 'texteditor-border-color': '@input-border', + 'texteditor-bg': '@input-bg', + 'texteditor-color': '@input-color', + 'texteditor-border-radius': '@input-border-radius', + 'texteditor-focused-border-color': '@input-border-focus', + 'texteditor-placeholder-color': '@input-color-placeholder', - 'pager-page-selected-bg': '@pagination-active-bg', - 'pager-page-selected-border-color': '@pagination-active-border', - 'pager-page-selected-color': '@pager-active-color', - 'pager-page-border-radius': '@pager-border-radius', + 'pager-page-selected-bg': '@pagination-active-bg', + 'pager-page-selected-border-color': '@pagination-active-border', + 'pager-page-selected-color': '@pager-active-color', + 'pager-page-border-radius': '@pager-border-radius', - 'tooltip-color': '@tooltip-color', - 'tooltip-bg': '@tooltip-bg', + 'tooltip-color': '@tooltip-color', + 'tooltip-bg': '@tooltip-bg', - 'overlay-content-bg': '@modal-content-bg', - 'overlay-border-color': '@modal-content-border-color', + 'overlay-content-bg': '@modal-content-bg', + 'overlay-border-color': '@modal-content-border-color', - 'progressbar-bg': '@progress-bg', - 'progressbar-border-color': '@progress-bar-color', - 'progressbar-range-bg': '@progress-bar-bg', + 'progressbar-bg': '@progress-bg', + 'progressbar-border-color': '@progress-bar-color', + 'progressbar-range-bg': '@progress-bar-bg', - 'list-border-color': '@list-group-border', - 'list-item-hover-bg': '@list-group-hover-bg', - 'list-item-selected-color': '@list-group-active-color', - 'list-item-selected-bg': '@list-group-active-bg', + 'list-border-color': '@list-group-border', + 'list-item-hover-bg': '@list-group-hover-bg', + 'list-item-selected-color': '@list-group-active-color', + 'list-item-selected-bg': '@list-group-active-bg', - 'badge-bg': '@badge-bg', - 'badge-color': '@badge-color' + 'badge-bg': '@badge-bg', + 'badge-color': '@badge-color', }; diff --git a/themebuilder-scss/src/data/bootstrap-metadata/bootstrap4-metadata.ts b/themebuilder-scss/src/data/bootstrap-metadata/bootstrap4-metadata.ts index 16be63f60a19..f19c7d13ac3f 100644 --- a/themebuilder-scss/src/data/bootstrap-metadata/bootstrap4-metadata.ts +++ b/themebuilder-scss/src/data/bootstrap-metadata/bootstrap4-metadata.ts @@ -1,60 +1,60 @@ export default { - 'base-font-family': '$font-family-sans-serif', - 'base-accent': '$primary', - 'base-bg': '$body-bg', - 'base-text-color': '$body-color', - 'base-border-color': '$table-border-color', + 'base-font-family': '$font-family-sans-serif', + 'base-accent': '$primary', + 'base-bg': '$body-bg', + 'base-text-color': '$body-color', + 'base-border-color': '$table-border-color', - 'base-border-radius': '$border-radius', - 'base-border-radius-large': '$border-radius-lg', - 'base-border-radius-small': '$border-radius-sm', + 'base-border-radius': '$border-radius', + 'base-border-radius-large': '$border-radius-lg', + 'base-border-radius-small': '$border-radius-sm', - 'base-success': '$success', - 'base-warning': '$warning', - 'base-danger': '$danger', + 'base-success': '$success', + 'base-warning': '$warning', + 'base-danger': '$danger', - 'base-link-color': '$link-color', - 'base-hover-color': '$table-hover-bg', + 'base-link-color': '$link-color', + 'base-hover-color': '$table-hover-bg', - 'button-normal-bg': '$light', - 'button-normal-border-color': '$light', + 'button-normal-bg': '$light', + 'button-normal-border-color': '$light', - 'button-default-bg': '$primary', - 'button-default-border-color': '$primary', + 'button-default-bg': '$primary', + 'button-default-border-color': '$primary', - 'button-success-bg': '$success', - 'button-success-border-color': '$success', + 'button-success-bg': '$success', + 'button-success-border-color': '$success', - 'button-danger-bg': '$danger', - 'button-danger-border-color': '$danger', + 'button-danger-bg': '$danger', + 'button-danger-border-color': '$danger', - 'button-border-radius': '$btn-border-radius', + 'button-border-radius': '$btn-border-radius', - 'texteditor-border-color': '$input-border-color', - 'texteditor-bg': '$input-bg', - 'texteditor-color': '$input-color', - 'texteditor-border-radius': '$input-border-radius', - 'texteditor-focused-border-color': '$input-focus-border-color', - 'texteditor-placeholder-color': '$input-placeholder-color', + 'texteditor-border-color': '$input-border-color', + 'texteditor-bg': '$input-bg', + 'texteditor-color': '$input-color', + 'texteditor-border-radius': '$input-border-radius', + 'texteditor-focused-border-color': '$input-focus-border-color', + 'texteditor-placeholder-color': '$input-placeholder-color', - 'pager-page-selected-bg': '$pagination-active-bg', - 'pager-page-selected-border-color': '$pagination-active-border-color', - 'pager-page-selected-color': '$pagination-active-color', + 'pager-page-selected-bg': '$pagination-active-bg', + 'pager-page-selected-border-color': '$pagination-active-border-color', + 'pager-page-selected-color': '$pagination-active-color', - 'tooltip-color': '$tooltip-color', - 'tooltip-bg': '$tooltip-bg', + 'tooltip-color': '$tooltip-color', + 'tooltip-bg': '$tooltip-bg', - 'overlay-content-bg': '$modal-content-bg', - 'overlay-border-color': '$modal-content-border-color', + 'overlay-content-bg': '$modal-content-bg', + 'overlay-border-color': '$modal-content-border-color', - 'progressbar-bg': '$progress-bg', - 'progressbar-border-color': '$progress-bar-color', - 'progressbar-range-bg': '$progress-bar-bg', + 'progressbar-bg': '$progress-bg', + 'progressbar-border-color': '$progress-bar-color', + 'progressbar-range-bg': '$progress-bar-bg', - 'list-border-color': '$list-group-border-color', - 'list-item-hover-bg': '$list-group-hover-bg', - 'list-item-selected-color': '$list-group-active-color', - 'list-item-selected-bg': '$list-group-active-bg', + 'list-border-color': '$list-group-border-color', + 'list-item-hover-bg': '$list-group-hover-bg', + 'list-item-selected-color': '$list-group-active-color', + 'list-item-selected-bg': '$list-group-active-bg', - 'badge-bg': '$primary' + 'badge-bg': '$primary', }; diff --git a/themebuilder-scss/src/data/migration-metadata/migration-metadata.ts b/themebuilder-scss/src/data/migration-metadata/migration-metadata.ts index 247c823a49c4..7016713e2713 100644 --- a/themebuilder-scss/src/data/migration-metadata/migration-metadata.ts +++ b/themebuilder-scss/src/data/migration-metadata/migration-metadata.ts @@ -1,120 +1,120 @@ export default { - generic: [ - '@radiogroup-checked-bg', - '@radiogroup-border-color', - '@radiogroup-bg', - '@radiobutton-active-bg', - '@radiogroup-hover-border-color', - '@radiobutton-focused-border-color', - '@accordion-color', - '@accordion-item-focused-border-color', - '@accordion-background-color', - '@accordion-title-active-color', - '@accordion-item-hover-bg', - '@accordion-title-active-bg', - '@checkbox-border-color', - '@checkbox-focused-borderd-color', - '@checkbox-bg', - '@checkbox-hover-border-color', - '@checkbox-active-icon-bg', - '@base-invalid-color', - '@base-invalid-faded-border-color', - '@list-border-color', - '@list-normal-color', - '@list-item-hover-bg', - '@list-item-focused-selected-bg', - '@list-focused-bg', - '@dropdowneditor-button-hover-bg', - '@dropdowneditor-button-active-bg', - '@tabs-border-color', - '@tabs-focused-border-color', - '@tabs-tab-hover-bg', - '@navbar-tab-focused-border-color', - '@switch-border-color', - '@switch-handle-active-bg', - '@switch-hover-border-color', - '@switch-focused-border-color', - '@switch-container-active-bg', - '@switch-active-border-color', - '@datagrid-base-color', - '@datagrid-base-background-color', - '@datagrid-border-color', - '@datagrid-hover-bg', - '@datagrid-row-hovered-color', - '@datagrid-nodata-color', - '@datagrid-link-color', - '@datagrid-columnchooser-bg', - '@PIVOTGRID_BORDER_COLOR', - '@PIVOTGRID_DATA_AREA_COLOR', - '@scheduler-cell-hover-bg', - '@SCHEDULER_PANEL_TEXT_COLOR', - '@SCHEDULER_WORKSPACE_BACKGROUND_COLOR', - '@SCHEDULER_WORKSPACE_ACCENT_COLOR', - '@menu-popup-bg', - '@menu-item-hover-bg', - '@menu-color', - '@menu-item-hovered-color', - '@menu-popup-border-color', - '@calendar-color', - '@calendar-hover-bg', - '@calendar-border-color', - '@calendar-cell-active-bg', - '@treeview-hover-bg', - '@treeview-border-color', - '@form-field-item-color', - '@filterbuilder-bg' - ], - material: [ - '@radiogroup-checked-bg', - '@radiogroup-border-color', - '@radiogroup-bg', - '@accordion-color', - '@accordion-background-color', - '@accordion-title-active-color', - '@accordion-item-hover-bg', - '@accordion-title-active-bg', - '@checkbox-border-color', - '@checkbox-bg', - '@checkbox-hover-border-color', - '@base-invalid-color', - '@base-invalid-faded-border-color', - '@list-border-color', - '@list-normal-color', - '@list-item-hover-bg', - '@list-item-focused-selected-bg', - '@navbar-tab-focused-border-color', - '@datagrid-base-color', - '@datagrid-base-background-color', - '@datagrid-border-color', - '@datagrid-hover-bg', - '@datagrid-row-hovered-color', - '@datagrid-nodata-color', - '@datagrid-link-color', - '@datagrid-columnchooser-bg', - '@PIVOTGRID_BORDER_COLOR', - '@PIVOTGRID_DATA_AREA_COLOR', - '@scheduler-cell-hover-bg', - '@SCHEDULER_PANEL_TEXT_COLOR', - '@SCHEDULER_WORKSPACE_BACKGROUND_COLOR', - '@SCHEDULER_WORKSPACE_ACCENT_COLOR', - '@menu-popup-bg', - '@menu-item-hover-bg', - '@menu-color', - '@menu-popup-border-color', - '@calendar-color', - '@calendar-hover-bg', - '@calendar-cell-active-bg', - '@treeview-hover-bg', - '@treeview-border-color', - '@form-field-item-color', - '@filterbuilder-bg', - '@datagrid-chevron-icon-color', - '@datagrid-filter-row-background-color', - '@datagrid-active-header-filter-icon-color', - '@datagrid-filter-panel-color', - '@pivotgrid-chevron-icon-color', - '@menu-item-expanded-color', - '@numberbox-spin-icon-color', - '@treeview-spin-icon-color' - ] + generic: [ + '@radiogroup-checked-bg', + '@radiogroup-border-color', + '@radiogroup-bg', + '@radiobutton-active-bg', + '@radiogroup-hover-border-color', + '@radiobutton-focused-border-color', + '@accordion-color', + '@accordion-item-focused-border-color', + '@accordion-background-color', + '@accordion-title-active-color', + '@accordion-item-hover-bg', + '@accordion-title-active-bg', + '@checkbox-border-color', + '@checkbox-focused-borderd-color', + '@checkbox-bg', + '@checkbox-hover-border-color', + '@checkbox-active-icon-bg', + '@base-invalid-color', + '@base-invalid-faded-border-color', + '@list-border-color', + '@list-normal-color', + '@list-item-hover-bg', + '@list-item-focused-selected-bg', + '@list-focused-bg', + '@dropdowneditor-button-hover-bg', + '@dropdowneditor-button-active-bg', + '@tabs-border-color', + '@tabs-focused-border-color', + '@tabs-tab-hover-bg', + '@navbar-tab-focused-border-color', + '@switch-border-color', + '@switch-handle-active-bg', + '@switch-hover-border-color', + '@switch-focused-border-color', + '@switch-container-active-bg', + '@switch-active-border-color', + '@datagrid-base-color', + '@datagrid-base-background-color', + '@datagrid-border-color', + '@datagrid-hover-bg', + '@datagrid-row-hovered-color', + '@datagrid-nodata-color', + '@datagrid-link-color', + '@datagrid-columnchooser-bg', + '@PIVOTGRID_BORDER_COLOR', + '@PIVOTGRID_DATA_AREA_COLOR', + '@scheduler-cell-hover-bg', + '@SCHEDULER_PANEL_TEXT_COLOR', + '@SCHEDULER_WORKSPACE_BACKGROUND_COLOR', + '@SCHEDULER_WORKSPACE_ACCENT_COLOR', + '@menu-popup-bg', + '@menu-item-hover-bg', + '@menu-color', + '@menu-item-hovered-color', + '@menu-popup-border-color', + '@calendar-color', + '@calendar-hover-bg', + '@calendar-border-color', + '@calendar-cell-active-bg', + '@treeview-hover-bg', + '@treeview-border-color', + '@form-field-item-color', + '@filterbuilder-bg', + ], + material: [ + '@radiogroup-checked-bg', + '@radiogroup-border-color', + '@radiogroup-bg', + '@accordion-color', + '@accordion-background-color', + '@accordion-title-active-color', + '@accordion-item-hover-bg', + '@accordion-title-active-bg', + '@checkbox-border-color', + '@checkbox-bg', + '@checkbox-hover-border-color', + '@base-invalid-color', + '@base-invalid-faded-border-color', + '@list-border-color', + '@list-normal-color', + '@list-item-hover-bg', + '@list-item-focused-selected-bg', + '@navbar-tab-focused-border-color', + '@datagrid-base-color', + '@datagrid-base-background-color', + '@datagrid-border-color', + '@datagrid-hover-bg', + '@datagrid-row-hovered-color', + '@datagrid-nodata-color', + '@datagrid-link-color', + '@datagrid-columnchooser-bg', + '@PIVOTGRID_BORDER_COLOR', + '@PIVOTGRID_DATA_AREA_COLOR', + '@scheduler-cell-hover-bg', + '@SCHEDULER_PANEL_TEXT_COLOR', + '@SCHEDULER_WORKSPACE_BACKGROUND_COLOR', + '@SCHEDULER_WORKSPACE_ACCENT_COLOR', + '@menu-popup-bg', + '@menu-item-hover-bg', + '@menu-color', + '@menu-popup-border-color', + '@calendar-color', + '@calendar-hover-bg', + '@calendar-cell-active-bg', + '@treeview-hover-bg', + '@treeview-border-color', + '@form-field-item-color', + '@filterbuilder-bg', + '@datagrid-chevron-icon-color', + '@datagrid-filter-row-background-color', + '@datagrid-active-header-filter-icon-color', + '@datagrid-filter-panel-color', + '@pivotgrid-chevron-icon-color', + '@menu-item-expanded-color', + '@numberbox-spin-icon-color', + '@treeview-spin-icon-color', + ], }; diff --git a/themebuilder-scss/src/metadata/collector.ts b/themebuilder-scss/src/metadata/collector.ts index c8d38ccba3df..b8a3c42a0498 100644 --- a/themebuilder-scss/src/metadata/collector.ts +++ b/themebuilder-scss/src/metadata/collector.ts @@ -1,58 +1,54 @@ import { promises as fs } from 'fs'; -import { resolve, relative, join, dirname } from 'path'; -import { MetadataGenerator } from './generator'; +import { + resolve, relative, join, dirname, +} from 'path'; +import MetadataGenerator from './generator'; -export class FileInfo { - constructor(path: string, content: string) { - this.path = path; - this.content = content; - } - path: string; - content: string; -} - -export class MetadataCollector { - generator = new MetadataGenerator(); +export default class MetadataCollector { + generator = new MetadataGenerator(); - async *getFileList(dirName: string): AsyncGenerator { - const directories = await fs.readdir(dirName, { withFileTypes: true }); - for(const directory of directories) { - const res = resolve(dirName, directory.name); - if(directory.isDirectory()) { - yield* this.getFileList(res); - } else { - yield res; - } - } - } + async getFileList(dirName: string): Promise> { + const directories = await fs.readdir(dirName, { withFileTypes: true }); + const files = await Promise.all(directories.map((directory) => { + const res = resolve(dirName, directory.name); + return directory.isDirectory() ? this.getFileList(res) : [res]; + })); + return Array.prototype.concat(...files); + } - async *readFiles(dirName: string, handler: (content: string) => string): AsyncGenerator { - const iterator = this.getFileList(dirName); + async readFiles( + dirName: string, + handler: (content: string) => string, + ): Promise> { + const fileList = await this.getFileList(dirName); - for await(const filePath of iterator) { - const realtivePath = relative(dirName, filePath); - const fileContent = await fs.readFile(filePath, 'utf-8'); - let modifiedContent = this.generator.collectMetadata(dirName, filePath, fileContent); - modifiedContent = handler(modifiedContent); - yield new FileInfo(realtivePath, modifiedContent); - } - } + return Promise.all(fileList.map(async (filePath) => { + const relativePath = relative(dirName, filePath); + const fileContent = await fs.readFile(filePath, 'utf-8'); + let modifiedContent = this.generator.collectMetadata(dirName, filePath, fileContent); + modifiedContent = handler(modifiedContent); + return { path: relativePath, content: modifiedContent }; + })); + } - async saveScssFiles(files: AsyncGenerator, destination: string): Promise { - for await(const file of files) { - const absolutePath = resolve(join(destination, file.path)); - const directory = dirname(absolutePath); - await fs.mkdir(directory, { recursive: true }); - await fs.writeFile(absolutePath, file.content); - } - } + static async saveScssFiles(files: Promise>, destination: string): Promise { + (await files).forEach(async (file) => { + const absolutePath = resolve(join(destination, file.path)); + const directory = dirname(absolutePath); + await fs.mkdir(directory, { recursive: true }); + await fs.writeFile(absolutePath, file.content); + }); + } - async saveMetadata(filePath: string, version: string) { - const absolutePath = resolve(filePath); - const metadata = this.generator.getMetadata(); - let metaContent = 'export const metadata: Array = ' + JSON.stringify(metadata) + ';\n'; - metaContent += `export const version: string = '${version}';\n`; - await fs.mkdir(dirname(absolutePath), { recursive: true }); - await fs.writeFile(absolutePath, metaContent); - } + async saveMetadata(filePath: string, version: string): Promise { + const absolutePath = resolve(filePath); + const metadata = this.generator.getMetadata(); + const metaString = JSON.stringify(metadata) + .replace(/"/g, '\'') + .replace(/'(ON|OFF)'/g, '"$1"'); // TODO test it! + let metaContent = `export const metadata: Array = ${metaString};\n`; + metaContent += `export const version: string = '${version}';\n`; + await fs.mkdir(dirname(absolutePath), { recursive: true }); + await fs.writeFile(absolutePath, metaContent); + } } diff --git a/themebuilder-scss/src/metadata/generate.ts b/themebuilder-scss/src/metadata/generate.ts index 4861ed572f1d..7911820feb13 100644 --- a/themebuilder-scss/src/metadata/generate.ts +++ b/themebuilder-scss/src/metadata/generate.ts @@ -1,4 +1,5 @@ -import { MetadataCollector } from './collector'; +/* eslint no-console: 0 */ +import MetadataCollector from './collector'; import { version } from '../../../build/gulp/context'; import { resolveDataUri } from '../../../build/gulp/gulp-data-uri'; @@ -9,16 +10,16 @@ const commentsRegex = /\s*\/\*[\S\s]*?\*\//g; const sourceHandler = (content: string): string => resolveDataUri(content.replace(commentsRegex, '')); -const generate = async () => { - try{ - const collector = new MetadataCollector(); - const soureFiles = collector.readFiles(stylesDirectory, sourceHandler); - await collector.saveScssFiles(soureFiles, stylesDestinationDirectory); - await collector.saveMetadata(metadataDestinationFile, version.package); - } catch(e) { - console.error(e); - process.exit(1); - } -} +const generate = async (): Promise => { + try { + const collector = new MetadataCollector(); + const sourceFiles = collector.readFiles(stylesDirectory, sourceHandler); + await MetadataCollector.saveScssFiles(sourceFiles, stylesDestinationDirectory); + await collector.saveMetadata(metadataDestinationFile, version.package); + } catch (e) { + console.error(e); + process.exit(1); + } +}; generate(); diff --git a/themebuilder-scss/src/metadata/generator.ts b/themebuilder-scss/src/metadata/generator.ts index 4f192a03f7e9..6f8b65965b57 100644 --- a/themebuilder-scss/src/metadata/generator.ts +++ b/themebuilder-scss/src/metadata/generator.ts @@ -1,86 +1,87 @@ -const path = require('path'); +import path from 'path'; -export class MetadataGenerator { - metadata: Array = []; +export default class MetadataGenerator { + metadata: Array = []; - capitalize(key: string): string { - return key.charAt(0).toUpperCase() + key.slice(1); - } + static capitalize(key: string): string { + return key.charAt(0).toUpperCase() + key.slice(1); + } - clean(): void { - this.metadata = []; - } + clean(): void { + this.metadata = []; + } - getMetadata(): Array { - return this.metadata; - } + getMetadata(): Array { + return this.metadata; + } - executor(str: string, regex: RegExp, handler: Function) { - let matches: RegExpMatchArray; - while((matches = regex.exec(str)) !== null) { - handler(matches); - } + static executor(str: string, regex: RegExp, handler: Function): void { + let matches = regex.exec(str); + while (matches !== null) { + handler(matches); + matches = regex.exec(str); } + } - parseComments(comments: string): MetaItem { - const metaItem: MetaItem = {}; + static parseComments(comments: string): MetaItem { + const metaItem: MetaItem = {}; - this.executor(comments, /\$(type|name|typeValues)\s(.+)/g, (matches: RegExpMatchArray) => { - const key = this.capitalize(matches[1]); - metaItem[key] = matches[2].trim(); - }); + MetadataGenerator.executor(comments, /\$(type|name|typeValues)\s(.+)/g, (matches: RegExpMatchArray) => { + const key = MetadataGenerator.capitalize(matches[1]); + metaItem[key] = matches[2].trim(); + }); - return metaItem; - } + return metaItem; + } - getMetaItems(scss: string): Array { - const metaItems: Array = []; + static getMetaItems(scss: string): Array { + const metaItems: Array = []; - this.executor(scss, /\/\*\*[\n\r]([\s\S]*?)\*\/\s*[\n\r]*([-$a-z_0-9]+):/gim, (matches: RegExpMatchArray) => { - const key = matches[2]; + MetadataGenerator.executor(scss, /\/\*\*[\n\r]([\s\S]*?)\*\/\s*[\n\r]*([-$a-z_0-9]+):/gim, (matches: RegExpMatchArray) => { + const key = matches[2]; - if(metaItems.some(item => item.Key === key)) return; + if (metaItems.some((item) => item.Key === key)) return; - const metaItem = { - 'Key': key - }; + const metaItem = { + Key: key, + }; - metaItems.push(Object.assign(metaItem, this.parseComments(matches[1]))); - }); + metaItems.push(Object.assign(metaItem, MetadataGenerator.parseComments(matches[1]))); + }); - return metaItems; - } + return metaItems; + } - normalizePath(scssDir: string, filePath: string): string { - return path.relative(scssDir, filePath) - .replace(/\\/g, '/') - .replace(/\.scss/, '') - .replace('_', '') - .replace(/^/, 'tb/'); - } - - getMapFromMeta(metaItems: Array, path: string): string { - let result = `"path": "${path}",\n`; - metaItems.forEach(item => { - result += `"${item.Key}": ${item.Key},\n`; - }); - return `(\n${result})`; - } + static normalizePath(scssDir: string, filePath: string): string { + return path.relative(scssDir, filePath) + .replace(/\\/g, '/') + .replace(/\.scss/, '') + .replace('_', '') + .replace(/^/, 'tb/'); + } - collectMetadata(scssDir: string, filePath: string, content: string): string { - const path = this.normalizePath(scssDir, filePath); - const metaItems = this.getMetaItems(content); + static getMapFromMeta(metaItems: Array, filePath: string): string { + let result = `\n"path": "${filePath}",\n`; + result += metaItems.map((item) => `"${item.Key}": ${item.Key},\n`).join(''); + return `(${result})`; + } - if(metaItems.length) { - metaItems.forEach(item => item.Path = path); - Array.prototype.push.apply(this.metadata, metaItems); + collectMetadata(scssDir: string, filePath: string, content: string): string { + const normalizedPath = MetadataGenerator.normalizePath(scssDir, filePath); + const metaItems = MetadataGenerator.getMetaItems(content); - const imports = `@forward "${path}";\n@use "${path}" as *;\n`; - const collector = `$never-used: collector(${this.getMapFromMeta(metaItems, path)});\n`; + if (metaItems.length) { + metaItems.forEach((item, index) => { + metaItems[index].Path = normalizedPath; + this.metadata.push(item); + }); - content = imports + content + collector; - } + const imports = `@forward "${normalizedPath}";\n@use "${normalizedPath}" as *;\n`; + const collector = `$never-used: collector(${MetadataGenerator.getMapFromMeta(metaItems, normalizedPath)});\n`; - return content; + return imports + content + collector; } + + return content; + } } diff --git a/themebuilder-scss/src/modules/base-parameters.ts b/themebuilder-scss/src/modules/base-parameters.ts index 069974004f0b..30355288c68d 100644 --- a/themebuilder-scss/src/modules/base-parameters.ts +++ b/themebuilder-scss/src/modules/base-parameters.ts @@ -1 +1 @@ -export const baseParameters: Array = ['@base-accent', '@base-text-color', '@base-bg', '@base-border-color', '@base-border-radius']; +export default ['@base-accent', '@base-text-color', '@base-bg', '@base-border-color', '@base-border-radius']; diff --git a/themebuilder-scss/src/modules/builder.ts b/themebuilder-scss/src/modules/builder.ts index 0b81b87aa130..511d28d66c11 100644 --- a/themebuilder-scss/src/modules/builder.ts +++ b/themebuilder-scss/src/modules/builder.ts @@ -1,17 +1,15 @@ import normalize from './config-normalizer'; -export class Builder { - constructor() {} - - buildTheme(config: ConfigSettings): void { - normalize(config); - // TODO return promise with - // compiledmetadata - compiler (+) - // css - compiler (+), - // swatchSelector - compiler (+), - // version - metadata (+), - // widgets - ? - // unusedWidgets - ? - } +export default class Builder { + static buildTheme(config: ConfigSettings): void { + normalize(config); + // TODO return promise with + // compiledmetadata - compiler (+) + // css - compiler (+), + // swatchSelector - compiler (+), + // version - metadata (+), + // widgets - ? + // unusedWidgets - ? + } } diff --git a/themebuilder-scss/src/modules/bundle-resolver.ts b/themebuilder-scss/src/modules/bundle-resolver.ts index 364b9dc16d6b..2a1f85a5f158 100644 --- a/themebuilder-scss/src/modules/bundle-resolver.ts +++ b/themebuilder-scss/src/modules/bundle-resolver.ts @@ -1,5 +1,5 @@ -export const resolveBundle = (theme: string, colorScheme: string) => { - colorScheme = colorScheme.replace(/-/g, '.'); - const themePart: string = (theme !== 'generic' ? theme + '.' : ''); - return `bundles/dx.${themePart}${colorScheme}.scss`; -} +export default (theme: string, colorScheme: string): string => { + const dottedColorScheme = colorScheme.replace(/-/g, '.'); + const themePart: string = (theme !== 'generic' ? `${theme}.` : ''); + return `bundles/dx.${themePart}${dottedColorScheme}.scss`; +}; diff --git a/themebuilder-scss/src/modules/clean-css-options.ts b/themebuilder-scss/src/modules/clean-css-options.ts index 36607b4b5bdc..e2b4d759172c 100644 --- a/themebuilder-scss/src/modules/clean-css-options.ts +++ b/themebuilder-scss/src/modules/clean-css-options.ts @@ -1,38 +1,36 @@ -import type CleanCSS from 'clean-css'; - // TODO we need to share this option with scss compiler (in gulp task) -export const cleanCssOptions: CleanCSS.Options = { - rebase: false, - format: { - breaks: { - afterAtRule: true, - afterBlockBegins: true, - afterBlockEnds: true, - afterComment: false, - afterProperty: true, - afterRuleBegins: true, - afterRuleEnds: true, - beforeBlockEnds: true, - betweenSelectors: true - }, - breakWith: '\n', - indentBy: 2, - indentWith: 'space', - spaces: { - aroundSelectorRelation: true, - beforeBlockBegins: true, - beforeValue: true - }, - wrapAt: false, +export default { + rebase: false, + format: { + breaks: { + afterAtRule: true, + afterBlockBegins: true, + afterBlockEnds: true, + afterComment: false, + afterProperty: true, + afterRuleBegins: true, + afterRuleEnds: true, + beforeBlockEnds: true, + betweenSelectors: true, + }, + breakWith: '\n', + indentBy: 2, + indentWith: 'space', + spaces: { + aroundSelectorRelation: true, + beforeBlockBegins: true, + beforeValue: true, + }, + wrapAt: false, + }, + level: { + 1: { + all: false, + semicolonAfterLastProperty: true, + }, + 2: { + all: true, }, - level: { - 1: { - all: false, - semicolonAfterLastProperty: true - }, - 2: { - all: true - } - } + }, }; diff --git a/themebuilder-scss/src/modules/commands.ts b/themebuilder-scss/src/modules/commands.ts index a1f6aeff1212..2c51be1f32f1 100644 --- a/themebuilder-scss/src/modules/commands.ts +++ b/themebuilder-scss/src/modules/commands.ts @@ -1,5 +1,5 @@ export default { - BUILD_THEME: 'build-theme', - BUILD_VARS: 'export-theme-vars', - BUILD_META: 'export-theme-meta' + BUILD_THEME: 'build-theme', + BUILD_VARS: 'export-theme-vars', + BUILD_META: 'export-theme-meta', }; diff --git a/themebuilder-scss/src/modules/compile-manager.ts b/themebuilder-scss/src/modules/compile-manager.ts index de989652dc18..833ece863690 100644 --- a/themebuilder-scss/src/modules/compile-manager.ts +++ b/themebuilder-scss/src/modules/compile-manager.ts @@ -1,37 +1,35 @@ -import { Compiler } from './compiler'; -import { PreCompiler } from './pre-compiler'; -import { resolveBundle } from './bundle-resolver'; -import { PostCompiler } from './post-compiler'; +import Compiler from './compiler'; +import PreCompiler from './pre-compiler'; +import resolveBundle from './bundle-resolver'; +import PostCompiler from './post-compiler'; -export class CompileManager { - compiler = new Compiler(); +export default class CompileManager { + compiler = new Compiler(); - async compile(config: ConfigSettings): Promise { - const bundle = resolveBundle(config.themeName, config.colorScheme); - const items = config.items; + async compile(config: ConfigSettings): Promise { + const bundle = resolveBundle(config.themeName, config.colorScheme); + const { items } = config; - try { - const data = await this.compiler.compile(bundle, items, null); - let css = data.result.css; + try { + const data = await this.compiler.compile(bundle, items, null); + let css = data.result.css.toString(); - if(config.makeSwatch) { - const preCompiler = new PreCompiler(); - const swatchSass = preCompiler.createSassForSwatch(config.outColorScheme, css); - const swatchResult = await this.compiler.compile(bundle, [], { data: swatchSass }); - css = swatchResult.result.css; - } + if (config.makeSwatch) { + const swatchSass = PreCompiler.createSassForSwatch(config.outColorScheme, css); + const swatchResult = await this.compiler.compile(bundle, [], { data: swatchSass }); + css = swatchResult.result.css.toString(); + } - if(config.assetsBasePath) { - const postCompiler = new PostCompiler(); - css = postCompiler.addBasePath(css, config.assetsBasePath); - } + if (config.assetsBasePath) { + css = PostCompiler.addBasePath(css, config.assetsBasePath); + } - return { - compiledMetadata: data.changedVariables, - css: css.toString() - }; - } catch(e) { - throw new Error(`Compilation failed. bundle: ${bundle}, e: ${e}`); - } + return { + compiledMetadata: data.changedVariables, + css: css.toString(), + }; + } catch (e) { + throw new Error(`Compilation failed. bundle: ${bundle}, e: ${e}`); } + } } diff --git a/themebuilder-scss/src/modules/compiler.ts b/themebuilder-scss/src/modules/compiler.ts index 1ea3c3471866..0fb4eec5e15e 100644 --- a/themebuilder-scss/src/modules/compiler.ts +++ b/themebuilder-scss/src/modules/compiler.ts @@ -1,94 +1,100 @@ import * as sass from 'sass'; import { metadata } from '../data/metadata/dx-theme-builder-metadata'; -export class Compiler { - changedVariables: Array = []; - importerCache: Record = {}; - meta: Array = metadata; - userItems: Array = []; - - compile(bundlePath: string, items: Array, customOptions: sass.SyncOptions): Promise { - this.changedVariables = []; - this.userItems = items || []; - - let compilerOptions: sass.SyncOptions = { - file: bundlePath, - importer: this.setter.bind(this), - functions: { - 'collector($map)': this.collector.bind(this) - } - }; - - if(customOptions) { - compilerOptions = { ...compilerOptions, ...customOptions }; - } +export default class Compiler { + changedVariables: Array = []; - return new Promise((resolve, reject) => { - try { - const result = sass.renderSync(compilerOptions); - this.importerCache = {}; - resolve({ - result, - changedVariables: this.changedVariables - }); - } catch(e) { - reject(e); - } - }); - } + importerCache: Record = {}; + + meta: Array = metadata; - getMatchingUserItemsAsString(url: string): string { - const metaKeysForUrl: Array = this.meta - .filter(item => item.Path === url) - .map(item => item.Key); + userItems: Array = []; - return this.userItems - .filter(item => metaKeysForUrl.indexOf(item.key) >= 0) - .map(item => `${item.key}: ${item.value};`) - .join(''); + compile( + bundlePath: string, + items: Array, + customOptions: sass.SyncOptions, + ): Promise { + this.changedVariables = []; + this.userItems = items || []; + + let compilerOptions: sass.SyncOptions = { + file: bundlePath, + importer: this.setter.bind(this), + functions: { + 'collector($map)': this.collector.bind(this), + }, + }; + + if (customOptions) { + compilerOptions = { ...compilerOptions, ...customOptions }; } - setter(url: string, _: any): sass.ImporterReturnType { - let content = this.importerCache[url]; + return new Promise((resolve, reject) => { + try { + const result = sass.renderSync(compilerOptions); + this.importerCache = {}; + resolve({ + result, + changedVariables: this.changedVariables, + }); + } catch (e) { + reject(e); + } + }); + } - if(!content) { - content = this.getMatchingUserItemsAsString(url); - this.importerCache[url] = content; - } + getMatchingUserItemsAsString(url: string): string { + const metaKeysForUrl: Array = this.meta + .filter((item) => item.Path === url) + .map((item) => item.Key); - return { contents: content }; + return this.userItems + .filter((item) => metaKeysForUrl.indexOf(item.key) >= 0) + .map((item) => `${item.key}: ${item.value};`) + .join(''); + } + + setter(url: string): sass.ImporterReturnType { + let content = this.importerCache[url]; + + if (!content) { + content = this.getMatchingUserItemsAsString(url); + this.importerCache[url] = content; } - collector(map: sass.types.Map): sass.types.ReturnValue { - const path = (map.getValue(0)).getValue(); - - for(let i = 1; i < map.getLength(); i++) { - const value = map.getValue(i); - let variableValue; - - if(value instanceof sass.types.Color) { - variableValue = `rgba(${value.getR()},${value.getG()},${value.getB()},${value.getA()})`; - } else if(value instanceof sass.types.String) { - variableValue = value.getValue(); - } else if(value instanceof sass.types.Number) { - variableValue = `${value.getValue()}${value.getUnit()}`; - } else if(value instanceof sass.types.List) { - const listValues = []; - for(let i = 0; i < value.getLength(); i++) { - listValues.push(value.getValue(i)); - } - variableValue = listValues.join(value.getSeparator() ? ',' : ' '); - } else { - return sass.types.Null.NULL; - } - - this.changedVariables.push({ - Key: (map.getKey(i)).getValue(), - Value: variableValue, - Path: path - }); + return { contents: content }; + } + + collector(map: sass.types.Map): sass.types.ReturnValue { + const path = (map.getValue(0) as sass.types.String).getValue(); + + for (let mapIndex = 1; mapIndex < map.getLength(); mapIndex += 1) { + const value = map.getValue(mapIndex); + let variableValue; + + if (value instanceof sass.types.Color) { + variableValue = `rgba(${value.getR()},${value.getG()},${value.getB()},${value.getA()})`; + } else if (value instanceof sass.types.String) { + variableValue = value.getValue(); + } else if (value instanceof sass.types.Number) { + variableValue = `${value.getValue()}${value.getUnit()}`; + } else if (value instanceof sass.types.List) { + const listValues = []; + for (let listIndex = 0; listIndex < value.getLength(); listIndex += 1) { + listValues.push(value.getValue(listIndex)); } + variableValue = listValues.join(value.getSeparator() ? ',' : ' '); + } else { return sass.types.Null.NULL; + } + + this.changedVariables.push({ + Key: (map.getKey(mapIndex) as sass.types.String).getValue(), + Value: variableValue, + Path: path, + }); } + return sass.types.Null.NULL; + } } - diff --git a/themebuilder-scss/src/modules/config-normalizer.ts b/themebuilder-scss/src/modules/config-normalizer.ts index 7645c1646ab9..56a6a39b4298 100644 --- a/themebuilder-scss/src/modules/config-normalizer.ts +++ b/themebuilder-scss/src/modules/config-normalizer.ts @@ -1,5 +1,5 @@ -/* global console */ /* eslint no-console: 0 */ +/* eslint no-param-reassign: ["error", { "props": false }] */ import commands from './commands'; import themes from './themes'; @@ -9,103 +9,120 @@ const DEFAULT_OUT_COLOR_SCHEME = 'custom-scheme'; const extname = (filename: string): string => filename.substring(filename.lastIndexOf('.')); const getBootstrapConfig = (fileName: string): ConfigSettings => { - const extension = extname(fileName); - let bootstrap = false; - let version = 0; - - if(extension === '.scss') { - bootstrap = true; - version = 4; - } else if(extension === '.less') { - bootstrap = true; - version = 3; - } + const extension = extname(fileName); + let bootstrap = false; + let version = 0; + + if (extension === '.scss') { + bootstrap = true; + version = 4; + } else if (extension === '.less') { + bootstrap = true; + version = 3; + } + + return { isBootstrap: bootstrap, bootstrapVersion: version }; +}; - return { isBootstrap: bootstrap, bootstrapVersion: version }; +const getOutParameters = ( + command: string, + themeName: string, + config: ConfigSettings, +): ConfigSettings => { + let outputFile = config.outputFile || ''; + let outColorScheme = config.outputColorScheme || ''; + let fileFormat = config.outputFormat || extname(outputFile).substr(1); + + const makeSwatch = !!config.makeSwatch; + const base = !!config.base; + const isColorSchemeValid = outColorScheme && /^[\w\-.]+$/.test(outColorScheme); + + if (!isColorSchemeValid) { + console.log( + `'--output-color-scheme' is not valid. '${DEFAULT_OUT_COLOR_SCHEME}' will be used.`, + ); + } + + if (!outColorScheme || !isColorSchemeValid) { + outColorScheme = DEFAULT_OUT_COLOR_SCHEME; + } + + if (!fileFormat) { + switch (command) { + case commands.BUILD_THEME: + fileFormat = 'css'; + break; + case commands.BUILD_VARS: + fileFormat = 'less'; + break; + case commands.BUILD_META: + fileFormat = 'json'; + break; + default: + fileFormat = 'css'; + break; + } + } + + if (!outputFile) { + outputFile = `dx.${themeName}.${outColorScheme}.${fileFormat}`; + } + + return { + outputFile, + fileFormat, + outColorScheme, + makeSwatch, + base, + }; }; -const getOutParameters = (command: string, themeName: string, config: ConfigSettings): ConfigSettings => { - let outputFile = config.outputFile || ''; - let outColorScheme = config.outputColorScheme || ''; - let fileFormat = config.outputFormat || extname(outputFile).substr(1); +const getThemeAndColorScheme = (config: ConfigSettings): ConfigSettings => { + let themeName = 'generic'; + let colorScheme = 'light'; + let foundTheme = null; - const makeSwatch = !!config.makeSwatch; - const base = !!config.base; + if (config.baseTheme) { + const dotIndex = config.baseTheme.indexOf('.'); + const passedThemeName = config.baseTheme.substr(0, dotIndex); + const passedColorScheme = config.baseTheme.substr(dotIndex + 1).replace(/\./g, '-'); - if(!outColorScheme) { - outColorScheme = DEFAULT_OUT_COLOR_SCHEME; - } else if(!/^[\w\-.]+$/.test(outColorScheme)) { - console.log(`'--output-color-scheme' is not valid. '${DEFAULT_OUT_COLOR_SCHEME}' will be used.`); - outColorScheme = DEFAULT_OUT_COLOR_SCHEME; - } + console.log(passedThemeName, passedColorScheme); - if(!fileFormat) { - switch(command) { - case commands.BUILD_THEME: - fileFormat = 'css'; - break; - case commands.BUILD_VARS: - fileFormat = 'less'; - break; - case commands.BUILD_META: - fileFormat = 'json'; - break; - } - } + foundTheme = themes.find((t) => t.name === passedThemeName + && t.colorScheme === passedColorScheme); - if(!outputFile) { - outputFile = 'dx.' + themeName + '.' + outColorScheme + '.' + fileFormat; + if (!foundTheme) { + console.log(`The base theme with name ${config.baseTheme} does not exist.`); } - - return { - outputFile: outputFile, - fileFormat: fileFormat, - outColorScheme: outColorScheme, - makeSwatch: makeSwatch, - base: base - }; -}; - -const getThemeAndColorScheme = (config: ConfigSettings): ConfigSettings => { - let themeName = 'generic'; - let colorScheme = 'light'; - let foundTheme = null; - - if(config.baseTheme) { - const dotIndex = config.baseTheme.indexOf('.'); - const passedThemeName = config.baseTheme.substr(0, dotIndex); - const passedColorScheme = config.baseTheme.substr(dotIndex + 1).replace(/\./g, '-'); - - console.log(passedThemeName, passedColorScheme); - - foundTheme = themes.find(t => t.name === passedThemeName && t.colorScheme === passedColorScheme); - if(!foundTheme) { - console.log(`The base theme with name ${config.baseTheme} does not exist.`); - } - } else if(config.themeId) { - foundTheme = themes.find(t => t.themeId === parseInt(config.themeId.toString())); - if(!foundTheme) { - console.log(`The theme with ID ${config.themeId} does not exist.`); - } + } else if (config.themeId) { + foundTheme = themes.find((t) => t.themeId === parseInt(config.themeId.toString(), 10)); + if (!foundTheme) { + console.log(`The theme with ID ${config.themeId} does not exist.`); } + } - if(foundTheme) { - themeName = foundTheme.name; - colorScheme = foundTheme.colorScheme; - } + if (foundTheme) { + themeName = foundTheme.name; + colorScheme = foundTheme.colorScheme; + } - return { - themeName: themeName, - colorScheme: colorScheme - }; + return { + themeName, + colorScheme, + }; }; -const replaceItemKeys = (config: ConfigSettings, searchValue: RegExp, replaceValue: string): void => { - if(config.items && config.items.length) { - config.items.forEach(item => { - item.key = item.key.replace(searchValue, replaceValue); - }); - } +const replaceItemKeys = ( + config: ConfigSettings, + searchValue: RegExp, + replaceValue: string, +): void => { + if (config.items && config.items.length) { + config.items.forEach((item) => { + item.key = item.key.replace(searchValue, replaceValue); + }); + } }; const convertTreeListConstants = (config: ConfigSettings): void => replaceItemKeys(config, /@treelist/, '@datagrid'); @@ -115,44 +132,42 @@ const convertItemKeysToSassFormat = (config: ConfigSettings): void => replaceIte const normalizePath = (path: string): string => path + (path[path.length - 1] !== '/' ? '/' : ''); const parseConfig = (config: ConfigSettings): void => { - const command = config.command; - const metadataFilePath = config.inputFile || ''; - const themeInfo = getThemeAndColorScheme(config); - const bootstrapConfig = getBootstrapConfig(metadataFilePath); - const output = getOutParameters(command, themeInfo.themeName, config); - - delete config.baseTheme; - delete config.outputColorScheme; - delete config.outputFormat; - delete config.outputFile; - delete config.inputFile; - delete config.themeId; - - if(config.lessPath) { - config.lessPath = normalizePath(config.lessPath); - } - - if(config.scssPath) { - config.scssPath = normalizePath(config.scssPath); - } - - convertTreeListConstants(config); - convertItemKeysToSassFormat(config); - - Object.assign(config, { - data: config.data !== undefined ? config.data : {}, - fileFormat: output.fileFormat, - themeName: themeInfo.themeName, - colorScheme: themeInfo.colorScheme, - outColorScheme: output.outColorScheme, - isBootstrap: bootstrapConfig.isBootstrap, - bootstrapVersion: bootstrapConfig.bootstrapVersion, - out: output.outputFile, - makeSwatch: output.makeSwatch, - base: output.base - }); + const { command } = config; + const metadataFilePath = config.inputFile || ''; + const themeInfo = getThemeAndColorScheme(config); + const bootstrapConfig = getBootstrapConfig(metadataFilePath); + const output = getOutParameters(command, themeInfo.themeName, config); + + delete config.baseTheme; + delete config.outputColorScheme; + delete config.outputFormat; + delete config.outputFile; + delete config.inputFile; + delete config.themeId; + + if (config.lessPath) { + config.lessPath = normalizePath(config.lessPath); + } + + if (config.scssPath) { + config.scssPath = normalizePath(config.scssPath); + } + + convertTreeListConstants(config); + convertItemKeysToSassFormat(config); + + Object.assign(config, { + data: config.data !== undefined ? config.data : {}, + fileFormat: output.fileFormat, + themeName: themeInfo.themeName, + colorScheme: themeInfo.colorScheme, + outColorScheme: output.outColorScheme, + isBootstrap: bootstrapConfig.isBootstrap, + bootstrapVersion: bootstrapConfig.bootstrapVersion, + out: output.outputFile, + makeSwatch: output.makeSwatch, + base: output.base, + }); }; export default parseConfig; - - diff --git a/themebuilder-scss/src/modules/post-compiler.ts b/themebuilder-scss/src/modules/post-compiler.ts index 6d83196978a0..f24f18be3a9e 100644 --- a/themebuilder-scss/src/modules/post-compiler.ts +++ b/themebuilder-scss/src/modules/post-compiler.ts @@ -1,6 +1,6 @@ -export class PostCompiler { - addBasePath(css: string | Buffer, basePath: string): string { - const normalizedPath = basePath.replace(/[\/\\]$/, '') + '/'; - return css.toString().replace(/(url\()("|')?(icons|fonts)/g, `$1$2${normalizedPath}$3`); - } +export default class PostCompiler { + static addBasePath(css: string | Buffer, basePath: string): string { + const normalizedPath = `${basePath.replace(/[/\\]$/, '')}/`; + return css.toString().replace(/(url\()("|')?(icons|fonts)/g, `$1$2${normalizedPath}$3`); + } } diff --git a/themebuilder-scss/src/modules/pre-compiler.ts b/themebuilder-scss/src/modules/pre-compiler.ts index eca9637ad5ea..d3f20d02971a 100644 --- a/themebuilder-scss/src/modules/pre-compiler.ts +++ b/themebuilder-scss/src/modules/pre-compiler.ts @@ -1,9 +1,8 @@ const SWATCH_SELECTOR_PREFIX = '.dx-swatch-'; -export class PreCompiler { - createSassForSwatch(outColorScheme: string, sass: string | Buffer): string { - const selector: string = SWATCH_SELECTOR_PREFIX + outColorScheme; - return `${selector} { ${sass} };`; - } +export default class PreCompiler { + static createSassForSwatch(outColorScheme: string, sass: string | Buffer): string { + const selector: string = SWATCH_SELECTOR_PREFIX + outColorScheme; + return `${selector} { ${sass} };`; + } } - diff --git a/themebuilder-scss/src/modules/themes.ts b/themebuilder-scss/src/modules/themes.ts index 337a9353aa25..1cee535e5c88 100644 --- a/themebuilder-scss/src/modules/themes.ts +++ b/themebuilder-scss/src/modules/themes.ts @@ -1,48 +1,118 @@ interface Theme { - themeId: Number; - name: string; - colorScheme: string; - text: string; - group: string; + themeId: number; + name: string; + colorScheme: string; + text: string; + group: string; } const themes: Array = [ - { themeId: 1, name: 'generic', colorScheme: 'light', text: 'Light', group: 'Generic' }, - { themeId: 2, name: 'generic', colorScheme: 'dark', text: 'Dark', group: 'Generic' }, - { themeId: 13, name: 'generic', colorScheme: 'carmine', text: 'Carmine', group: 'Generic' }, - { themeId: 14, name: 'generic', colorScheme: 'darkmoon', text: 'Dark Moon', group: 'Generic' }, - { themeId: 15, name: 'generic', colorScheme: 'softblue', text: 'Soft Blue', group: 'Generic' }, - { themeId: 16, name: 'generic', colorScheme: 'darkviolet', text: 'Dark Violet', group: 'Generic' }, - { themeId: 17, name: 'generic', colorScheme: 'greenmist', text: 'Green Mist', group: 'Generic' }, - { themeId: 9, name: 'generic', colorScheme: 'light-compact', text: 'Light', group: 'Generic Compact' }, - { themeId: 10, name: 'generic', colorScheme: 'dark-compact', text: 'Dark', group: 'Generic Compact' }, - { themeId: 18, name: 'generic', colorScheme: 'carmine-compact', text: 'Carmine', group: 'Generic Compact' }, - { themeId: 19, name: 'generic', colorScheme: 'darkmoon-compact', text: 'Dark Moon', group: 'Generic Compact' }, - { themeId: 20, name: 'generic', colorScheme: 'softblue-compact', text: 'Soft Blue', group: 'Generic Compact' }, - { themeId: 21, name: 'generic', colorScheme: 'darkviolet-compact', text: 'Dark Violet', group: 'Generic Compact' }, - { themeId: 22, name: 'generic', colorScheme: 'greenmist-compact', text: 'Green Mist', group: 'Generic Compact' }, - { themeId: 23, name: 'material', colorScheme: 'blue-light', text: 'Blue Light', group: 'Material Design' }, - { themeId: 28, name: 'material', colorScheme: 'blue-dark', text: 'Blue Dark', group: 'Material Design' }, - { themeId: 24, name: 'material', colorScheme: 'orange-light', text: 'Orange Light', group: 'Material Design' }, - { themeId: 29, name: 'material', colorScheme: 'orange-dark', text: 'Orange Dark', group: 'Material Design' }, - { themeId: 25, name: 'material', colorScheme: 'lime-light', text: 'Lime Light', group: 'Material Design' }, - { themeId: 30, name: 'material', colorScheme: 'lime-dark', text: 'Lime Dark', group: 'Material Design' }, - { themeId: 26, name: 'material', colorScheme: 'purple-light', text: 'Purple Light', group: 'Material Design' }, - { themeId: 31, name: 'material', colorScheme: 'purple-dark', text: 'Purple Dark', group: 'Material Design' }, - { themeId: 27, name: 'material', colorScheme: 'teal-light', text: 'Teal Light', group: 'Material Design' }, - { themeId: 32, name: 'material', colorScheme: 'teal-dark', text: 'Teal Dark', group: 'Material Design' }, + { + themeId: 1, name: 'generic', colorScheme: 'light', text: 'Light', group: 'Generic', + }, + { + themeId: 2, name: 'generic', colorScheme: 'dark', text: 'Dark', group: 'Generic', + }, + { + themeId: 13, name: 'generic', colorScheme: 'carmine', text: 'Carmine', group: 'Generic', + }, + { + themeId: 14, name: 'generic', colorScheme: 'darkmoon', text: 'Dark Moon', group: 'Generic', + }, + { + themeId: 15, name: 'generic', colorScheme: 'softblue', text: 'Soft Blue', group: 'Generic', + }, + { + themeId: 16, name: 'generic', colorScheme: 'darkviolet', text: 'Dark Violet', group: 'Generic', + }, + { + themeId: 17, name: 'generic', colorScheme: 'greenmist', text: 'Green Mist', group: 'Generic', + }, + { + themeId: 9, name: 'generic', colorScheme: 'light-compact', text: 'Light', group: 'Generic Compact', + }, + { + themeId: 10, name: 'generic', colorScheme: 'dark-compact', text: 'Dark', group: 'Generic Compact', + }, + { + themeId: 18, name: 'generic', colorScheme: 'carmine-compact', text: 'Carmine', group: 'Generic Compact', + }, + { + themeId: 19, name: 'generic', colorScheme: 'darkmoon-compact', text: 'Dark Moon', group: 'Generic Compact', + }, + { + themeId: 20, name: 'generic', colorScheme: 'softblue-compact', text: 'Soft Blue', group: 'Generic Compact', + }, + { + themeId: 21, name: 'generic', colorScheme: 'darkviolet-compact', text: 'Dark Violet', group: 'Generic Compact', + }, + { + themeId: 22, name: 'generic', colorScheme: 'greenmist-compact', text: 'Green Mist', group: 'Generic Compact', + }, + { + themeId: 23, name: 'material', colorScheme: 'blue-light', text: 'Blue Light', group: 'Material Design', + }, + { + themeId: 28, name: 'material', colorScheme: 'blue-dark', text: 'Blue Dark', group: 'Material Design', + }, + { + themeId: 24, name: 'material', colorScheme: 'orange-light', text: 'Orange Light', group: 'Material Design', + }, + { + themeId: 29, name: 'material', colorScheme: 'orange-dark', text: 'Orange Dark', group: 'Material Design', + }, + { + themeId: 25, name: 'material', colorScheme: 'lime-light', text: 'Lime Light', group: 'Material Design', + }, + { + themeId: 30, name: 'material', colorScheme: 'lime-dark', text: 'Lime Dark', group: 'Material Design', + }, + { + themeId: 26, name: 'material', colorScheme: 'purple-light', text: 'Purple Light', group: 'Material Design', + }, + { + themeId: 31, name: 'material', colorScheme: 'purple-dark', text: 'Purple Dark', group: 'Material Design', + }, + { + themeId: 27, name: 'material', colorScheme: 'teal-light', text: 'Teal Light', group: 'Material Design', + }, + { + themeId: 32, name: 'material', colorScheme: 'teal-dark', text: 'Teal Dark', group: 'Material Design', + }, - { themeId: 33, name: 'material', colorScheme: 'blue-light-compact', text: 'Blue Light Compact', group: 'Material Design (Compact)' }, - { themeId: 34, name: 'material', colorScheme: 'blue-dark-compact', text: 'Blue Dark Compact', group: 'Material Design (Compact)' }, - { themeId: 35, name: 'material', colorScheme: 'orange-light-compact', text: 'Orange Light Compact', group: 'Material Design (Compact)' }, - { themeId: 36, name: 'material', colorScheme: 'orange-dark-compact', text: 'Orange Dark Compact', group: 'Material Design (Compact)' }, - { themeId: 37, name: 'material', colorScheme: 'lime-light-compact', text: 'Lime Light Compact', group: 'Material Design (Compact)' }, - { themeId: 38, name: 'material', colorScheme: 'lime-dark-compact', text: 'Lime Dark Compact', group: 'Material Design (Compact)' }, - { themeId: 39, name: 'material', colorScheme: 'purple-light-compact', text: 'Purple Light Compact', group: 'Material Design (Compact)' }, - { themeId: 40, name: 'material', colorScheme: 'purple-dark-compact', text: 'Purple Dark Compact', group: 'Material Design (Compact)' }, - { themeId: 41, name: 'material', colorScheme: 'teal-light-compact', text: 'Teal Light Compact', group: 'Material Design (Compact)' }, - { themeId: 42, name: 'material', colorScheme: 'teal-dark-compact', text: 'Teal Dark Compact', group: 'Material Design (Compact)' }, + { + themeId: 33, name: 'material', colorScheme: 'blue-light-compact', text: 'Blue Light Compact', group: 'Material Design (Compact)', + }, + { + themeId: 34, name: 'material', colorScheme: 'blue-dark-compact', text: 'Blue Dark Compact', group: 'Material Design (Compact)', + }, + { + themeId: 35, name: 'material', colorScheme: 'orange-light-compact', text: 'Orange Light Compact', group: 'Material Design (Compact)', + }, + { + themeId: 36, name: 'material', colorScheme: 'orange-dark-compact', text: 'Orange Dark Compact', group: 'Material Design (Compact)', + }, + { + themeId: 37, name: 'material', colorScheme: 'lime-light-compact', text: 'Lime Light Compact', group: 'Material Design (Compact)', + }, + { + themeId: 38, name: 'material', colorScheme: 'lime-dark-compact', text: 'Lime Dark Compact', group: 'Material Design (Compact)', + }, + { + themeId: 39, name: 'material', colorScheme: 'purple-light-compact', text: 'Purple Light Compact', group: 'Material Design (Compact)', + }, + { + themeId: 40, name: 'material', colorScheme: 'purple-dark-compact', text: 'Purple Dark Compact', group: 'Material Design (Compact)', + }, + { + themeId: 41, name: 'material', colorScheme: 'teal-light-compact', text: 'Teal Light Compact', group: 'Material Design (Compact)', + }, + { + themeId: 42, name: 'material', colorScheme: 'teal-dark-compact', text: 'Teal Dark Compact', group: 'Material Design (Compact)', + }, - { themeId: 3, name: 'ios7', colorScheme: 'default', text: 'iOS', group: 'Mobile' } + { + themeId: 3, name: 'ios7', colorScheme: 'default', text: 'iOS', group: 'Mobile', + }, ]; export default themes; diff --git a/themebuilder-scss/src/types/types.ts b/themebuilder-scss/src/types/types.ts index 46d20db6c260..cc4aa94bbe46 100644 --- a/themebuilder-scss/src/types/types.ts +++ b/themebuilder-scss/src/types/types.ts @@ -1,61 +1,70 @@ interface MetaItem { - Key?: string; - Name?: string; - Value?: string; - Type?: string; - TypeValues?: string; - Path?: string; - [key: string]: string; + Key?: string; + Name?: string; + Value?: string; + Type?: string; + TypeValues?: string; + Path?: string; + [key: string]: string; } interface ConfigMetaItem { - key: string; - value: string; + key: string; + value: string; +} + +interface LessCompilerInterface { + render: Function; } interface ConfigSettings { - themeName?: string; - colorScheme?: string; - makeSwatch?: boolean; - outColorScheme?: string; - assetsBasePath?: string; - base?: boolean; - items?: Array; - data?: string; - widgets?: Array + themeName?: string; + colorScheme?: string; + makeSwatch?: boolean; + outColorScheme?: string; + assetsBasePath?: string; + base?: boolean; + items?: Array; + data?: string; + widgets?: Array; - fileFormat?: string; - baseTheme?: string; - themeId?: string | number; + fileFormat?: string; + baseTheme?: string; + themeId?: string | number; - isBootstrap?: boolean; - bootstrapVersion?: number; + isBootstrap?: boolean; + bootstrapVersion?: number; - outputFile?: string; - outputColorScheme?: string; - outputFormat?: string; + outputFile?: string; + outputColorScheme?: string; + outputFormat?: string; - command?: string; - inputFile?: string; - lessPath?: string; - scssPath?: string; - out?: string; // TODO need? + command?: string; + inputFile?: string; + lessPath?: string; + scssPath?: string; + out?: string; // TODO need? - reader?: Function; //TODO need? - lessCompiler?: any; //TODO need? + reader?: Function; // TODO need? + lessCompiler?: LessCompilerInterface; // TODO need? } interface CompilerResult { - result: any; // TODO we need node-sass -> Result type here - changedVariables: Array; + result: import('node-sass').Result; + changedVariables: Array; } interface PackageResult { - css: string; - compiledMetadata: Array; + css: string; + compiledMetadata: Array; } interface Metadata { - metadata: Array; - version: string; + metadata: Array; + version: string; +} + +interface FileInfo { + path: string; + content: string; } diff --git a/themebuilder-scss/tests/.eslintrc b/themebuilder-scss/tests/.eslintrc new file mode 100644 index 000000000000..c797ba88dbf9 --- /dev/null +++ b/themebuilder-scss/tests/.eslintrc @@ -0,0 +1,8 @@ +{ + "extends": [ + "devextreme/jest" + ], + "parserOptions": { + "project": "tests/tsconfig.json" + } +} \ No newline at end of file diff --git a/themebuilder-scss/tests/data/compilation-results/no-changes-meta.ts b/themebuilder-scss/tests/data/compilation-results/no-changes-meta.ts index ec146da68776..7c9a393c4620 100644 --- a/themebuilder-scss/tests/data/compilation-results/no-changes-meta.ts +++ b/themebuilder-scss/tests/data/compilation-results/no-changes-meta.ts @@ -1,24 +1,24 @@ const meta: Array = [ - { - Key: '$base-font-family', - Value: '"Helvetica Neue","Segoe UI",Helvetica,Verdana,sans-serif', - Path: 'tb/widgets/generic/colors' - }, - { - Key: '$base-accent', - Value: 'rgba(51,122,183,1)', - Path: 'tb/widgets/generic/colors' - }, - { - Key: '$accordion-title-color', - Value: 'rgba(51,122,183,1)', - Path: 'tb/widgets/generic/accordion/colors' - }, - { - Key: '$accordion-item-title-opened-bg', - Value: 'rgba(0,0,0,0)', - Path: 'tb/widgets/generic/accordion/colors' - } + { + Key: '$base-font-family', + Value: '"Helvetica Neue","Segoe UI",Helvetica,Verdana,sans-serif', + Path: 'tb/widgets/generic/colors', + }, + { + Key: '$base-accent', + Value: 'rgba(51,122,183,1)', + Path: 'tb/widgets/generic/colors', + }, + { + Key: '$accordion-title-color', + Value: 'rgba(51,122,183,1)', + Path: 'tb/widgets/generic/accordion/colors', + }, + { + Key: '$accordion-item-title-opened-bg', + Value: 'rgba(0,0,0,0)', + Path: 'tb/widgets/generic/accordion/colors', + }, ]; export default meta; diff --git a/themebuilder-scss/tests/data/metadata.ts b/themebuilder-scss/tests/data/metadata.ts index f205085f8902..5eb0c16de910 100644 --- a/themebuilder-scss/tests/data/metadata.ts +++ b/themebuilder-scss/tests/data/metadata.ts @@ -1,7 +1,15 @@ export const metadata: Array = [ - { 'Key': '$base-font-family', 'Name': '', 'Type': 'text', 'Path': 'tb/widgets/generic/colors' }, - { 'Key': '$base-accent', 'Name': '', 'Type': 'color', 'Path': 'tb/widgets/generic/colors' }, - { 'Key': '$accordion-title-color', 'Name': '', 'Type': 'color', 'Path': 'tb/widgets/generic/accordion/colors' }, - { 'Key': '$accordion-item-title-opened-bg', 'Name': '', 'Type': 'color', 'Path': 'tb/widgets/generic/accordion/colors' } + { + Key: '$base-font-family', Name: '', Type: 'text', Path: 'tb/widgets/generic/colors', + }, + { + Key: '$base-accent', Name: '', Type: 'color', Path: 'tb/widgets/generic/colors', + }, + { + Key: '$accordion-title-color', Name: '', Type: 'color', Path: 'tb/widgets/generic/accordion/colors', + }, + { + Key: '$accordion-item-title-opened-bg', Name: '', Type: 'color', Path: 'tb/widgets/generic/accordion/colors', + }, ]; -export const version: string = ''; +export const version = ''; diff --git a/themebuilder-scss/tests/metadata/collector.test.ts b/themebuilder-scss/tests/metadata/collector.test.ts index de0d498408e3..614d21a4b71e 100644 --- a/themebuilder-scss/tests/metadata/collector.test.ts +++ b/themebuilder-scss/tests/metadata/collector.test.ts @@ -1,103 +1,90 @@ import { join, resolve, dirname } from 'path'; import { promises } from 'fs'; -import { MetadataCollector, FileInfo } from '../../src/metadata/collector'; +import MetadataCollector from '../../src/metadata/collector'; const rootDir = join(__dirname, '..', '..'); const scssDir = join(rootDir, 'tests', 'data', 'scss'); describe('MetadataCollector', () => { - const expectedFileList: Array = [ - join('bundles', 'dx.light.scss'), - join('widgets', 'generic', 'accordion', '_colors.scss'), - join('widgets', 'generic', 'accordion', '_index.scss'), - join('widgets', 'generic', 'accordion', '_sizes.scss'), - join('widgets', 'generic', '_colors.scss'), - join('widgets', 'generic', '_index.scss'), - join('widgets', 'generic', '_sizes.scss') - ]; - - promises.mkdir = jest.fn(); - promises.writeFile = jest.fn(); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - test('getFileList', async () => { - const collector = new MetadataCollector(); - const iterator = collector.getFileList(join(rootDir, 'tests', 'data', 'scss')); - const fileList: Array = []; - - for await(const file of iterator) { - fileList.push(file); - } - - expect(fileList).toEqual(expectedFileList.map(file => join(scssDir, file))); - }); - - test('readFiles', async () => { - const collector = new MetadataCollector(); - const handler = (content: string) => content; - const iterator = collector.readFiles(join(rootDir, 'tests', 'data', 'scss'), handler); - const filesInfo: Array = []; - - for await(const file of iterator) { - filesInfo.push(file); - } - - expect(filesInfo.map(file => file.path)).toEqual(expectedFileList); - - filesInfo.forEach(file => { - expect(file.content).not.toBeFalsy(); - expect(file.content.length > 0).toBeTruthy(); - }); - }); - - test('readFiles handle files with additional handler', async () => { - const collector = new MetadataCollector(); - const handler = (content: string) => '123' + content; - const iterator = collector.readFiles(join(rootDir, 'tests', 'data', 'scss'), handler); - - for await(const file of iterator) { - expect(file.content.slice(0, 3)).toBe('123'); - } - }); - - test('saveScssFile', async () => { - const collector = new MetadataCollector(); - const relativePath = join('path', 'filePath.scss'); - const fileContent = 'file content'; - const destinationPath = './scss'; - const expectedDestinationPath = resolve(join(destinationPath, relativePath)); - const expectedDestinationDir = dirname(expectedDestinationPath); - - async function* getTestFiles(): AsyncGenerator { - yield new FileInfo(relativePath, fileContent); - } - - await collector.saveScssFiles(getTestFiles(), destinationPath); - - expect(promises.mkdir).toHaveBeenCalledTimes(1); - expect(promises.mkdir).toHaveBeenCalledWith(expectedDestinationDir, { recursive: true }); - expect(promises.writeFile).toHaveBeenCalledTimes(1); - expect(promises.writeFile).toHaveBeenCalledWith(expectedDestinationPath, fileContent); - }); - - test('saveMetadata', async () => { - const collector = new MetadataCollector(); - const version = '1.1.1'; - const fileName = join('metadata', 'dx-theme-builder-metadata.ts'); - const expectedFileName = resolve(fileName); - const expectedDirName = dirname(expectedFileName); - let metaContent = 'export const metadata: Array = ' + JSON.stringify([]) + ';\n'; - metaContent += `export const version: string = '${version}';\n`; - - await collector.saveMetadata(fileName, version); - - expect(promises.mkdir).toHaveBeenCalledTimes(1); - expect(promises.mkdir).toHaveBeenCalledWith(expectedDirName, { recursive: true }); - expect(promises.writeFile).toHaveBeenCalledTimes(1); - expect(promises.writeFile).toHaveBeenCalledWith(expectedFileName, metaContent); + const expectedFileList: Array = [ + join('bundles', 'dx.light.scss'), + join('widgets', 'generic', 'accordion', '_colors.scss'), + join('widgets', 'generic', 'accordion', '_index.scss'), + join('widgets', 'generic', 'accordion', '_sizes.scss'), + join('widgets', 'generic', '_colors.scss'), + join('widgets', 'generic', '_index.scss'), + join('widgets', 'generic', '_sizes.scss'), + ]; + + promises.mkdir = jest.fn(); + promises.writeFile = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + test('getFileList', async () => { + const collector = new MetadataCollector(); + const fileList = await collector.getFileList(join(rootDir, 'tests', 'data', 'scss')); + + expect(fileList).toEqual(expectedFileList.map((file) => join(scssDir, file))); + }); + + test('readFiles', async () => { + const collector = new MetadataCollector(); + const handler = (content: string): string => content; + const filesInfo = await collector.readFiles(join(rootDir, 'tests', 'data', 'scss'), handler); + + expect(filesInfo.map((file) => file.path)).toEqual(expectedFileList); + + filesInfo.forEach((file) => { + expect(typeof file.content).toBe('string'); + expect(file.content.length).toBeGreaterThan(0); }); + }); + + test('readFiles handle files with additional handler', async () => { + const collector = new MetadataCollector(); + const handler = (content: string): string => `123${content}`; + const fileList = await collector.readFiles(join(rootDir, 'tests', 'data', 'scss'), handler); + + fileList.forEach((file) => expect(file.content.slice(0, 3)).toBe('123')); + }); + + test('saveScssFile', async () => { + const relativePath = join('path', 'filePath.scss'); + const fileContent = 'file content'; + const destinationPath = './scss'; + const expectedDestinationPath = resolve(join(destinationPath, relativePath)); + const expectedDestinationDir = dirname(expectedDestinationPath); + + async function getTestFiles(): Promise> { + return [{ path: relativePath, content: fileContent }]; + } + + await MetadataCollector.saveScssFiles(getTestFiles(), destinationPath); + + expect(promises.mkdir).toHaveBeenCalledTimes(1); + expect(promises.mkdir).toHaveBeenCalledWith(expectedDestinationDir, { recursive: true }); + expect(promises.writeFile).toHaveBeenCalledTimes(1); + expect(promises.writeFile).toHaveBeenCalledWith(expectedDestinationPath, fileContent); + }); + + test('saveMetadata', async () => { + const collector = new MetadataCollector(); + const version = '1.1.1'; + const fileName = join('metadata', 'dx-theme-builder-metadata.ts'); + const expectedFileName = resolve(fileName); + const expectedDirName = dirname(expectedFileName); + let metaContent = `export const metadata: Array = ${JSON.stringify([])};\n`; + metaContent += `export const version: string = '${version}';\n`; + + await collector.saveMetadata(fileName, version); + + expect(promises.mkdir).toHaveBeenCalledTimes(1); + expect(promises.mkdir).toHaveBeenCalledWith(expectedDirName, { recursive: true }); + expect(promises.writeFile).toHaveBeenCalledTimes(1); + expect(promises.writeFile).toHaveBeenCalledWith(expectedFileName, metaContent); + }); }); diff --git a/themebuilder-scss/tests/metadata/generator.test.ts b/themebuilder-scss/tests/metadata/generator.test.ts index f9b3e113954b..d29937f4431a 100644 --- a/themebuilder-scss/tests/metadata/generator.test.ts +++ b/themebuilder-scss/tests/metadata/generator.test.ts @@ -1,55 +1,55 @@ -import { MetadataGenerator } from '../../src/metadata/generator'; +import MetadataGenerator from '../../src/metadata/generator'; const generator = new MetadataGenerator(); describe('Metadata generator - parseComments', () => { - const commentSamples: Array = [ - '* $name 10. Constant name', - '* $wrong some wrong comment', - '* $name 10. Name\n* $type select\n* $typeValues 1|2' - ]; - - test('name parsed correctly', () => { - expect(generator.parseComments(commentSamples[0])).toEqual({ 'Name': '10. Constant name' }); - }); - - test('allowed only variables parsed', () => { - expect(generator.parseComments(commentSamples[1])).toEqual({}); - }); - - test('multiple variables parsed', () => { - expect(generator.parseComments(commentSamples[2])).toEqual({ - 'Name': '10. Name', - 'Type': 'select', - 'TypeValues': '1|2' - }); + const commentSamples: Array = [ + '* $name 10. Constant name', + '* $wrong some wrong comment', + '* $name 10. Name\n* $type select\n* $typeValues 1|2', + ]; + + test('name parsed correctly', () => { + expect(MetadataGenerator.parseComments(commentSamples[0])).toEqual({ Name: '10. Constant name' }); + }); + + test('allowed only variables parsed', () => { + expect(MetadataGenerator.parseComments(commentSamples[1])).toEqual({}); + }); + + test('multiple variables parsed', () => { + expect(MetadataGenerator.parseComments(commentSamples[2])).toEqual({ + Name: '10. Name', + Type: 'select', + TypeValues: '1|2', }); + }); }); describe('Metadata generator - getMetaItems (one item)', () => { - interface Samples { - [key: string]: string - } + interface Samples { + [key: string]: string; + } - const scssSamples: Array = [ - { - 'no new line after comment': + const scssSamples: Array = [ + { + 'no new line after comment': `/** * $name Slide out background * $type color */ -$slideout-background: #000;` - }, { - '2 new lines after comment': +$slideout-background: #000;`, + }, { + '2 new lines after comment': `/** * $name Slide out background * $type color */ -$slideout-background: #000;` - }, { - 'extra constant before comment': +$slideout-background: #000;`, + }, { + 'extra constant before comment': ` $base-color: rgb(0,170,0); /** @@ -57,31 +57,31 @@ $base-color: rgb(0,170,0); * $type color */ -$slideout-background: $base-color;` - }, { - 'spaces after comments': +$slideout-background: $base-color;`, + }, { + 'spaces after comments': `/** * $name Slide out background * $type color */ -$slideout-background: #000;` - }]; - - scssSamples.forEach((sample) => { - const key = Object.keys(sample)[0]; - test(key, () => { - expect(generator.getMetaItems(sample[key])).toEqual([{ - 'Name': 'Slide out background', - 'Type': 'color', - 'Key': '$slideout-background' - }]); - }); +$slideout-background: #000;`, + }]; + + scssSamples.forEach((sample) => { + const key = Object.keys(sample)[0]; + + test(key, () => { + expect(MetadataGenerator.getMetaItems(sample[key])).toEqual([{ + Name: 'Slide out background', + Type: 'color', + Key: '$slideout-background', + }]); }); + }); }); describe('Metadata generator - getMetaItems (several item)', () => { - const sample = -`/** + const sample = `/** * $name Slide out background * $type color */ @@ -108,24 +108,23 @@ $slideout-background2: $base-color; */ $slideout-background3: #000;`; - test('parse several items', () => { - const result = generator.getMetaItems(sample); + test('parse several items', () => { + const result = MetadataGenerator.getMetaItems(sample); - expect(result.length).toBe(4); + expect(result.length).toBe(4); - result.forEach((item, index) => { - expect(item).toEqual({ - 'Name': 'Slide out background', - 'Type': 'color', - 'Key': `$slideout-background${index}` - }); - }); + result.forEach((item, index) => { + expect(item).toEqual({ + Name: 'Slide out background', + Type: 'color', + Key: `$slideout-background${index}`, + }); }); + }); }); describe('Metadata generator - getMetaItems (duplicates removed, only first description used)', () => { - const sample = -`/** + const sample = `/** * $name Slide out background1 * $type color */ @@ -141,69 +140,71 @@ $slideout-background: #000; $base-color: rgb(0,170,0); `; - test('parse items with duplicates', () => { - const result = generator.getMetaItems(sample); + test('parse items with duplicates', () => { + const result = MetadataGenerator.getMetaItems(sample); - expect(result.length).toBe(1); + expect(result.length).toBe(1); - expect(result[0]).toEqual({ - 'Name': 'Slide out background1', - 'Type': 'color', - 'Key': '$slideout-background' - }); + expect(result[0]).toEqual({ + Name: 'Slide out background1', + Type: 'color', + Key: '$slideout-background', }); + }); }); describe('Metadata generator - normalizePath', () => { - interface TestData { - scssPath: string; - path: string; - expected: string; - } - - const matrix: Array = [ - { scssPath: '/scss', path: '/scss/widgets/generic/toolbar/_colors.scss', expected: 'tb/widgets/generic/toolbar/colors' }, - { scssPath: '/scss', path: '/scss/widgets/generic/navBar/_colors.scss', expected: 'tb/widgets/generic/navBar/colors' }, - { scssPath: '/repo/scss', path: '/repo/scss/widgets/generic/toolbar/_sizes.scss', expected: 'tb/widgets/generic/toolbar/sizes' }, - { scssPath: '/repo/scss', path: '/repo/scss/widgets/generic/toolbar/_sizes.scss', expected: 'tb/widgets/generic/toolbar/sizes' }, - { scssPath: '/repo/../scss', path: '/scss/widgets/generic/toolbar/_sizes.scss', expected: 'tb/widgets/generic/toolbar/sizes' }, - { scssPath: '/repo/../scss', path: '/repo/../scss/widgets/generic/toolbar/_sizes.scss', expected: 'tb/widgets/generic/toolbar/sizes' }, - { scssPath: 'd:\\repo\\scss', path: 'd:\\repo\\scss\\widgets\\generic\\toolbar\\_colors.scss', expected: 'tb/widgets/generic/toolbar/colors' }, - { scssPath: 'd:\\repo\\scss', path: 'd:\\repo\\scss\\widgets\\generic\\toolbar\\_colors.scss', expected: 'tb/widgets/generic/toolbar/colors' }, - ]; - test('normalizePath works as expected', () => { - matrix.forEach((item) => { - expect(generator.normalizePath(item.scssPath, item.path)).toBe(item.expected); - }); + interface TestData { + scssPath: string; + path: string; + expected: string; + } + + const matrix: Array = [ + { scssPath: '/scss', path: '/scss/widgets/generic/toolbar/_colors.scss', expected: 'tb/widgets/generic/toolbar/colors' }, + { scssPath: '/scss', path: '/scss/widgets/generic/navBar/_colors.scss', expected: 'tb/widgets/generic/navBar/colors' }, + { scssPath: '/repo/scss', path: '/repo/scss/widgets/generic/toolbar/_sizes.scss', expected: 'tb/widgets/generic/toolbar/sizes' }, + { scssPath: '/repo/scss', path: '/repo/scss/widgets/generic/toolbar/_sizes.scss', expected: 'tb/widgets/generic/toolbar/sizes' }, + { scssPath: '/repo/../scss', path: '/scss/widgets/generic/toolbar/_sizes.scss', expected: 'tb/widgets/generic/toolbar/sizes' }, + { scssPath: '/repo/../scss', path: '/repo/../scss/widgets/generic/toolbar/_sizes.scss', expected: 'tb/widgets/generic/toolbar/sizes' }, + { scssPath: 'd:\\repo\\scss', path: 'd:\\repo\\scss\\widgets\\generic\\toolbar\\_colors.scss', expected: 'tb/widgets/generic/toolbar/colors' }, + { scssPath: 'd:\\repo\\scss', path: 'd:\\repo\\scss\\widgets\\generic\\toolbar\\_colors.scss', expected: 'tb/widgets/generic/toolbar/colors' }, + ]; + + test('normalizePath works as expected', () => { + matrix.forEach((item) => { + expect(MetadataGenerator.normalizePath(item.scssPath, item.path)).toBe(item.expected); }); + }); }); describe('Metadata generator - getMapFromMeta', () => { - const testMetadata: Array = [ - { 'Key': '$menu-color' }, - { 'Key': '$menu-item-selected-bg' } - ]; - test('getMapFromMeta works as expected', () => { - expect(generator.getMapFromMeta(testMetadata, '/')) - .toBe('(\n"path": "/",\n"$menu-color": $menu-color,\n"$menu-item-selected-bg": $menu-item-selected-bg,\n)'); - }); + const testMetadata: Array = [ + { Key: '$menu-color' }, + { Key: '$menu-item-selected-bg' }, + ]; + + test('getMapFromMeta works as expected', () => { + expect(MetadataGenerator.getMapFromMeta(testMetadata, '/')) + .toBe('(\n"path": "/",\n"$menu-color": $menu-color,\n"$menu-item-selected-bg": $menu-item-selected-bg,\n)'); + }); }); describe('Metadata generator - collectMetadata', () => { - test('collectMetadata for file without comments return the same content and add nothing to metadata', () => { - const scssPath = '/scss'; - const path = '/scss/widgets/generic/toolbar/_colors.scss'; - const content = '@use "colors";'; - - const result = generator.collectMetadata(scssPath, path, content); - expect(content).toBe(result); - expect(generator.getMetadata()).toEqual([]); - }); - - test('collectMetadata for file with comments modify file content and add data to metadata', () => { - const scssPath = '/scss'; - const path = '/scss/widgets/generic/toolbar/_colors.scss'; - const content = ` + test('collectMetadata for file without comments return the same content and add nothing to metadata', () => { + const scssPath = '/scss'; + const path = '/scss/widgets/generic/toolbar/_colors.scss'; + const content = '@use "colors";'; + + const result = generator.collectMetadata(scssPath, path, content); + expect(content).toBe(result); + expect(generator.getMetadata()).toEqual([]); + }); + + test('collectMetadata for file with comments modify file content and add data to metadata', () => { + const scssPath = '/scss'; + const path = '/scss/widgets/generic/toolbar/_colors.scss'; + const content = ` @use "colors"; /** * $name Slide out background @@ -212,8 +213,7 @@ describe('Metadata generator - collectMetadata', () => { $slideout-background: #000; `; - const expected = -`@forward "tb/widgets/generic/toolbar/colors"; + const expected = `@forward "tb/widgets/generic/toolbar/colors"; @use "tb/widgets/generic/toolbar/colors" as *; @use "colors"; @@ -228,28 +228,28 @@ $never-used: collector(( )); `; - const result = generator.collectMetadata(scssPath, path, content); - expect(expected).toBe(result); - expect(generator.getMetadata()).toEqual([{ - 'Name': 'Slide out background', - 'Type': 'color', - 'Key': '$slideout-background', - 'Path': 'tb/widgets/generic/toolbar/colors' - }]); - }); - - test('clean method clean metadata', () => { - // metadata is not empty because of the previous test - expect(generator.getMetadata()).not.toEqual([]); - generator.clean(); - expect(generator.getMetadata()).toEqual([]); - }); - - test('collectMetadata add several item for different files with the same variables names', () => { - const scssPath = '/scss'; - const path1 = '/scss/widgets/generic/toolbar/_colors.scss'; - const path2 = '/scss/widgets/material/toolbar/_colors.scss'; - const content = ` + const result = generator.collectMetadata(scssPath, path, content); + expect(expected).toBe(result); + expect(generator.getMetadata()).toEqual([{ + Name: 'Slide out background', + Type: 'color', + Key: '$slideout-background', + Path: 'tb/widgets/generic/toolbar/colors', + }]); + }); + + test('clean method clean metadata', () => { + // metadata is not empty because of the previous test + expect(generator.getMetadata()).not.toEqual([]); + generator.clean(); + expect(generator.getMetadata()).toEqual([]); + }); + + test('collectMetadata add several item for different files with the same variables names', () => { + const scssPath = '/scss'; + const path1 = '/scss/widgets/generic/toolbar/_colors.scss'; + const path2 = '/scss/widgets/material/toolbar/_colors.scss'; + const content = ` @use "colors"; /** * $name Slide out background @@ -258,20 +258,19 @@ $never-used: collector(( $slideout-background: #000; `; - generator.collectMetadata(scssPath, path1, content); - generator.collectMetadata(scssPath, path2, content); - - expect(generator.getMetadata()).toEqual([{ - 'Name': 'Slide out background', - 'Type': 'color', - 'Key': '$slideout-background', - 'Path': 'tb/widgets/generic/toolbar/colors' - }, { - 'Name': 'Slide out background', - 'Type': 'color', - 'Key': '$slideout-background', - 'Path': 'tb/widgets/material/toolbar/colors' - }]); - }); + generator.collectMetadata(scssPath, path1, content); + generator.collectMetadata(scssPath, path2, content); + + expect(generator.getMetadata()).toEqual([{ + Name: 'Slide out background', + Type: 'color', + Key: '$slideout-background', + Path: 'tb/widgets/generic/toolbar/colors', + }, { + Name: 'Slide out background', + Type: 'color', + Key: '$slideout-background', + Path: 'tb/widgets/material/toolbar/colors', + }]); + }); }); - diff --git a/themebuilder-scss/tests/modules/bundle-resolver.test.ts b/themebuilder-scss/tests/modules/bundle-resolver.test.ts index 757fd0bd4ee1..4f4a1aa14f28 100644 --- a/themebuilder-scss/tests/modules/bundle-resolver.test.ts +++ b/themebuilder-scss/tests/modules/bundle-resolver.test.ts @@ -1,25 +1,24 @@ -import { resolveBundle } from '../../src/modules/bundle-resolver'; +import resolveBundle from '../../src/modules/bundle-resolver'; interface ThemeData { - theme: string; - colorScheme: string; - fileName: string; + theme: string; + colorScheme: string; + fileName: string; } describe('Bundle resolver', () => { - test('resolveBundle - the right filename is generated', () => { + test('resolveBundle - the right filename is generated', () => { + const fileNamesForThemes: Array = [ + { theme: 'generic', colorScheme: 'light', fileName: 'bundles/dx.light.scss' }, + { theme: 'generic', colorScheme: 'dark', fileName: 'bundles/dx.dark.scss' }, + { theme: 'generic', colorScheme: 'greenmist', fileName: 'bundles/dx.greenmist.scss' }, + { theme: 'generic', colorScheme: 'light-compact', fileName: 'bundles/dx.light.compact.scss' }, + { theme: 'material', colorScheme: 'blue-light', fileName: 'bundles/dx.material.blue.light.scss' }, + { theme: 'material', colorScheme: 'blue-light-compact', fileName: 'bundles/dx.material.blue.light.compact.scss' }, + ]; - const fileNamesForThemes: Array = [ - { theme: 'generic', colorScheme: 'light', fileName: 'bundles/dx.light.scss' }, - { theme: 'generic', colorScheme: 'dark', fileName: 'bundles/dx.dark.scss' }, - { theme: 'generic', colorScheme: 'greenmist', fileName: 'bundles/dx.greenmist.scss' }, - { theme: 'generic', colorScheme: 'light-compact', fileName: 'bundles/dx.light.compact.scss' }, - { theme: 'material', colorScheme: 'blue-light', fileName: 'bundles/dx.material.blue.light.scss' }, - { theme: 'material', colorScheme: 'blue-light-compact', fileName: 'bundles/dx.material.blue.light.compact.scss' } - ]; - - fileNamesForThemes.forEach((themeData: ThemeData) => { - expect(resolveBundle(themeData.theme, themeData.colorScheme)).toBe(themeData.fileName); - }); + fileNamesForThemes.forEach((themeData: ThemeData) => { + expect(resolveBundle(themeData.theme, themeData.colorScheme)).toBe(themeData.fileName); }); + }); }); diff --git a/themebuilder-scss/tests/modules/compile-manager.test.ts b/themebuilder-scss/tests/modules/compile-manager.test.ts index 4eae11eabee0..774596413c29 100644 --- a/themebuilder-scss/tests/modules/compile-manager.test.ts +++ b/themebuilder-scss/tests/modules/compile-manager.test.ts @@ -1,41 +1,38 @@ import path from 'path'; -import { ImportMock } from 'ts-mock-imports'; -import { CompileManager } from '../../src/modules/compile-manager'; - -import * as realMetadata from '../../src/data/metadata/dx-theme-builder-metadata'; -import * as bundleResolver from '../../src/modules/bundle-resolver'; import { metadata } from '../data/metadata'; - import noModificationsResult from '../data/compilation-results/no-changes-css'; import noModificationsMeta from '../data/compilation-results/no-changes-meta'; +import CompileManager from '../../src/modules/compile-manager'; + const dataPath = path.join(path.resolve(), 'tests', 'data'); -describe('Compile manager - integration test on test sass', () => { - beforeEach(() => { - ImportMock.mockOther(realMetadata, 'metadata', metadata); - ImportMock.mockOther(bundleResolver, 'resolveBundle', () => path.join(dataPath, 'scss', 'bundles', 'dx.light.scss')); - }); +jest.mock('../../src/modules/bundle-resolver', () => ({ + __esModule: true, + default: (): string => path.join(dataPath, 'scss', 'bundles', 'dx.light.scss'), +})); - afterEach(() => { - ImportMock.restore(); - }); +jest.mock('../../src/data/metadata/dx-theme-builder-metadata', () => ({ + __esModule: true, + metadata, +})); - test('compile test bundle without swatch', () => { - const manager = new CompileManager(); - return manager.compile({}).then(result => { - expect(result.css).toBe(noModificationsResult); - expect(result.compiledMetadata).toEqual(noModificationsMeta); - }); +describe('Compile manager - integration test on test sass', () => { + test('compile test bundle without swatch', () => { + const manager = new CompileManager(); + return manager.compile({}).then((result) => { + expect(result.css).toBe(noModificationsResult); + expect(result.compiledMetadata).toEqual(noModificationsMeta); }); + }); - test('compile test bundle with swatch', () => { - const manager = new CompileManager(); - return manager.compile({ - makeSwatch: true, - outColorScheme: 'test-theme' - }).then(result => { - expect(result.css).toBe(`.dx-swatch-test-theme .dx-accordion { + test('compile test bundle with swatch', () => { + const manager = new CompileManager(); + return manager.compile({ + makeSwatch: true, + outColorScheme: 'test-theme', + }).then((result) => { + expect(result.css).toBe(`.dx-swatch-test-theme .dx-accordion { background-color: "Helvetica Neue", "Segoe UI", Helvetica, Verdana, sans-serif; color: #337ab7; font: url("icons/icons.woff2"); @@ -44,16 +41,16 @@ describe('Compile manager - integration test on test sass', () => { background-color: transparent; color: #337ab7; }`); - expect(result.compiledMetadata).toEqual(noModificationsMeta); - }); + expect(result.compiledMetadata).toEqual(noModificationsMeta); }); + }); - test('compile test bundle with assetsBasePath', () => { - const manager = new CompileManager(); - return manager.compile({ - assetsBasePath: 'base-path' - }).then(result => { - expect(result.css).toBe(`.dx-accordion { + test('compile test bundle with assetsBasePath', () => { + const manager = new CompileManager(); + return manager.compile({ + assetsBasePath: 'base-path', + }).then((result) => { + expect(result.css).toBe(`.dx-accordion { background-color: "Helvetica Neue", "Segoe UI", Helvetica, Verdana, sans-serif; color: #337ab7; font: url("base-path/icons/icons.woff2"); @@ -62,15 +59,15 @@ describe('Compile manager - integration test on test sass', () => { background-color: transparent; color: #337ab7; }`); - expect(result.compiledMetadata).toEqual(noModificationsMeta); - }); + expect(result.compiledMetadata).toEqual(noModificationsMeta); }); + }); - test('compile test bundle with error', () => { - const manager = new CompileManager(); - expect(manager.compile({ - makeSwatch: true, - outColorScheme: 'error for sass compiler :)' - })).rejects.toBeTruthy(); - }); + test('compile test bundle with error', () => { + const manager = new CompileManager(); + return expect(manager.compile({ + makeSwatch: true, + outColorScheme: 'error for sass compiler :)', + })).rejects.toBeInstanceOf(Error); + }); }); diff --git a/themebuilder-scss/tests/modules/compiler-sass.test.ts b/themebuilder-scss/tests/modules/compiler-sass.test.ts new file mode 100644 index 000000000000..0d63d5bb1a4e --- /dev/null +++ b/themebuilder-scss/tests/modules/compiler-sass.test.ts @@ -0,0 +1,149 @@ + +import sass from 'sass'; + +import Compiler from '../../src/modules/compiler'; + +jest.mock('../../src/data/metadata/dx-theme-builder-metadata', () => ({ + __esModule: true, + metadata: [ + { + Key: '$var0', Name: '10. Font size', Type: 'text', Path: 'tb/path', + }, + { + Key: '$var1', Name: '10. Font family', Type: 'text', Path: 'tb/path', + }, + { + Key: '$var2', Name: '10. Accent color', Type: 'color', Path: 'tb/path', + }, + { + Key: '$var3', Name: '10. Select color', Type: 'color', Path: 'tb/another/path', + }, + ], +})); + + +describe('Sass features', () => { + test('collector function', () => { + const compiler = new Compiler(); + const map = new sass.types.Map(7); + + // path is always the first + map.setKey(0, new sass.types.String('path')); + map.setValue(0, new sass.types.String('tb/path')); + // number variable + map.setKey(1, new sass.types.String('$var1')); + map.setValue(1, new sass.types.Number(300, 'px')); + // string variable + map.setKey(2, new sass.types.String('$var2')); + map.setValue(2, new sass.types.String('Helvetica')); + // color variable + map.setKey(3, new sass.types.String('$var3')); + map.setValue(3, new sass.types.Color(50, 60, 70, 0.4)); + // list variable + map.setKey(4, new sass.types.String('$var4')); + const list1 = new sass.types.List(3); + list1.setValue(0, new sass.types.Number(10, 'px')); + list1.setValue(1, new sass.types.Number(15, 'px')); + list1.setValue(2, new sass.types.Number(32, 'px')); + list1.setSeparator(true); + map.setValue(4, list1); + // list variable with ',' + map.setKey(5, new sass.types.String('$var5')); + const list2 = new sass.types.List(3); + list2.setValue(0, new sass.types.Number(10, 'px')); + list2.setValue(1, new sass.types.Number(15, 'px')); + list2.setValue(2, new sass.types.Number(32, 'px')); + list2.setSeparator(false); + map.setValue(5, list2); + // null variable + map.setKey(6, new sass.types.String('$var6')); + map.setValue(6, sass.types.Null.NULL); + + compiler.collector(map); + + expect(compiler.changedVariables).toEqual([ + { Key: '$var1', Value: '300px', Path: 'tb/path' }, + { Key: '$var2', Value: 'Helvetica', Path: 'tb/path' }, + { Key: '$var3', Value: 'rgba(50,60,70,0.4)', Path: 'tb/path' }, + { Key: '$var4', Value: '10px,15px,32px', Path: 'tb/path' }, + { Key: '$var5', Value: '10px 15px 32px', Path: 'tb/path' }, + ]); + }); + + test('getMatchingUserItemsAsString - return right string for the url', () => { + const compiler = new Compiler(); + + const testCases = [ + { + userItems: [{ + key: '$var2', + value: 'rgba(0,0,0,0)', + }, { + key: '$var0', + value: '10px', + }], + url: 'tb/path', + expected: '$var2: rgba(0,0,0,0);$var0: 10px;', + }, + { + userItems: [{ + key: '$var2', + value: 'rgba(0,0,0,0)', + }], + url: 'tb/path', + expected: '$var2: rgba(0,0,0,0);', + }, + { + userItems: [{ + key: '$var3', + value: 'rgba(0,0,0,0)', + }], + url: 'tb/path', + expected: '', + }, + { + userItems: [{ + key: '$var3', + value: 'rgba(0,0,0,0)', + }], + url: 'tb/another/path', + expected: '$var3: rgba(0,0,0,0);', + }, + ]; + + testCases.forEach((testCase) => { + compiler.userItems = testCase.userItems; + + const content = compiler.getMatchingUserItemsAsString(testCase.url); + + expect(content).toEqual(testCase.expected); + }); + }); + + test('setter function (custom importer)', () => { + const compiler = new Compiler(); + compiler.userItems = [{ + key: '$var2', + value: 'rgba(0,0,0,0)', + }, { + key: '$var0', + value: '10px', + }]; + + const setterResult = compiler.setter('tb/path'); + expect(setterResult).toEqual({ contents: '$var2: rgba(0,0,0,0);$var0: 10px;' }); + expect(compiler.importerCache).toEqual({ 'tb/path': '$var2: rgba(0,0,0,0);$var0: 10px;' }); + }); + + test('setter call getMatchingUserItemsAsString once for every url', () => { + const url = 'path1'; + const compiler = new Compiler(); + compiler.getMatchingUserItemsAsString = jest.fn().mockImplementation(() => 'content'); + compiler.setter(url); + compiler.setter(url); + compiler.setter(url); + + expect(compiler.getMatchingUserItemsAsString).toHaveBeenCalledTimes(1); + expect(compiler.importerCache[url]).toBe('content'); + }); +}); diff --git a/themebuilder-scss/tests/modules/compiler.test.ts b/themebuilder-scss/tests/modules/compiler.test.ts index 975dc1bf9923..dc822d24afdd 100644 --- a/themebuilder-scss/tests/modules/compiler.test.ts +++ b/themebuilder-scss/tests/modules/compiler.test.ts @@ -1,46 +1,40 @@ -import { ImportMock } from 'ts-mock-imports'; -import sass from 'sass'; + import path from 'path'; import fs from 'fs'; -import * as realMetadata from '../../src/data/metadata/dx-theme-builder-metadata'; import { metadata } from '../data/metadata'; - -import { Compiler } from '../../src/modules/compiler'; import noModificationsResult from '../data/compilation-results/no-changes-css'; import noModificationsMeta from '../data/compilation-results/no-changes-meta'; -const dataPath: string = path.join(path.resolve(), 'tests', 'data'); +import Compiler from '../../src/modules/compiler'; -describe('compile', () => { - beforeEach(() => { - ImportMock.mockOther(realMetadata, 'metadata', metadata); - }); +jest.mock('../../src/data/metadata/dx-theme-builder-metadata', () => ({ + __esModule: true, + metadata, +})); - afterEach(() => { - ImportMock.restore(); - }); - - const bundle = path.join(dataPath, 'scss', 'bundles', 'dx.light.scss'); +const dataPath: string = path.join(path.resolve(), 'tests', 'data'); - test('Compile with empty modifications (check that items can be undefined)', () => { - // expect.assertions(2); - const compiler = new Compiler(); - return compiler.compile(bundle, null, null).then(data => { - // compiled css - expect(noModificationsResult).toBe(data.result.css.toString()); - // collected variables - expect(noModificationsMeta).toEqual(data.changedVariables); - }); +describe('compile', () => { + const bundle = path.join(dataPath, 'scss', 'bundles', 'dx.light.scss'); + + test('Compile with empty modifications (check that items can be undefined)', () => { + const compiler = new Compiler(); + return compiler.compile(bundle, null, null).then((data) => { + // compiled css + expect(noModificationsResult).toBe(data.result.css.toString()); + // collected variables + expect(noModificationsMeta).toEqual(data.changedVariables); }); - - test('Compile with one base and one accordion items modified', () => { - const compiler = new Compiler(); - return compiler.compile(bundle, [ - { key: '$base-accent', value: 'red' }, - { key: '$accordion-item-title-opened-bg', value: 'green' }, - ], null).then(data => { - // compiled css - expect(data.result.css.toString()).toBe(`.dx-accordion { + }); + + test('Compile with one base and one accordion items modified', () => { + const compiler = new Compiler(); + return compiler.compile(bundle, [ + { key: '$base-accent', value: 'red' }, + { key: '$accordion-item-title-opened-bg', value: 'green' }, + ], null).then((data) => { + // compiled css + expect(data.result.css.toString()).toBe(`.dx-accordion { background-color: "Helvetica Neue", "Segoe UI", Helvetica, Verdana, sans-serif; color: red; font: url("icons/icons.woff2"); @@ -49,193 +43,58 @@ describe('compile', () => { background-color: green; color: red; }`); - // collected variables - expect(data.changedVariables).toEqual([ - { - Key: '$base-font-family', - Value: '"Helvetica Neue","Segoe UI",Helvetica,Verdana,sans-serif', - Path: 'tb/widgets/generic/colors' - }, - { - Key: '$base-accent', - Value: 'rgba(255,0,0,1)', // red - Path: 'tb/widgets/generic/colors' - }, - { - Key: '$accordion-title-color', - Value: 'rgba(255,0,0,1)', // red - Path: 'tb/widgets/generic/accordion/colors' - }, - { - Key: '$accordion-item-title-opened-bg', - Value: 'rgba(0,128,0,1)', // green - Path: 'tb/widgets/generic/accordion/colors' - } - ]); - }); - }); - - test('Compile with error', () => { - const compiler = new Compiler(); - return compiler.compile('dx.error.scss', [], null).then( - data => expect(false).toBe(true), - error => { - expect(error.status).toBe(3); - expect(error.formatted).toBe('Error: dx.error.scss: no such file or directory'); - } - ); - }); - - test('Compile with custom sass compiler options (try to compile with custom data)', () => { - const compiler = new Compiler(); - const bundleContent = fs.readFileSync(bundle, 'utf8'); - const extraOptions = { - data: bundleContent + '.extra-class { color: red; }', - outputStyle: 'compressed' as const - }; - return compiler.compile(bundle, [], extraOptions).then(data => { - // compiled css - expect(data.result.css.toString()).toBe('.dx-accordion{background-color:"Helvetica Neue","Segoe UI",Helvetica,Verdana,sans-serif;\ -color:#337ab7;font:url("icons/icons.woff2")}.dx-accordion .from-base{background-color:transparent;color:#337ab7}.extra-class{color:red}'); - }); + // collected variables + expect(data.changedVariables).toEqual([ + { + Key: '$base-font-family', + Value: '"Helvetica Neue","Segoe UI",Helvetica,Verdana,sans-serif', + Path: 'tb/widgets/generic/colors', + }, + { + Key: '$base-accent', + Value: 'rgba(255,0,0,1)', // red + Path: 'tb/widgets/generic/colors', + }, + { + Key: '$accordion-title-color', + Value: 'rgba(255,0,0,1)', // red + Path: 'tb/widgets/generic/accordion/colors', + }, + { + Key: '$accordion-item-title-opened-bg', + Value: 'rgba(0,128,0,1)', // green + Path: 'tb/widgets/generic/accordion/colors', + }, + ]); }); -}); - -describe('Sass features', () => { - beforeEach(() => { - ImportMock.mockOther(realMetadata, 'metadata', [ - { 'Key': '$var0', 'Name': '10. Font size', 'Type': 'text', 'Path': 'tb/path' }, - { 'Key': '$var1', 'Name': '10. Font family', 'Type': 'text', 'Path': 'tb/path' }, - { 'Key': '$var2', 'Name': '10. Accent color', 'Type': 'color', 'Path': 'tb/path' }, - { 'Key': '$var3', 'Name': '10. Select color', 'Type': 'color', 'Path': 'tb/another/path' } - ]); - }); - - afterEach(() => { - ImportMock.restore(); - }); - - test('collector function', () => { - const compiler = new Compiler(); - const map = new sass.types.Map(7); - - // path is always the first - map.setKey(0, new sass.types.String('path')); - map.setValue(0, new sass.types.String('tb/path')); - // number variable - map.setKey(1, new sass.types.String('$var1')); - map.setValue(1, new sass.types.Number(300, 'px')); - // string variable - map.setKey(2, new sass.types.String('$var2')); - map.setValue(2, new sass.types.String('Helvetica')); - // color variable - map.setKey(3, new sass.types.String('$var3')); - map.setValue(3, new sass.types.Color(50, 60, 70, 0.4)); - // list variable - map.setKey(4, new sass.types.String('$var4')); - const list1 = new sass.types.List(3); - list1.setValue(0, new sass.types.Number(10, 'px')); - list1.setValue(1, new sass.types.Number(15, 'px')); - list1.setValue(2, new sass.types.Number(32, 'px')); - list1.setSeparator(true); - map.setValue(4, list1); - // list variable with ',' - map.setKey(5, new sass.types.String('$var5')); - const list2 = new sass.types.List(3); - list2.setValue(0, new sass.types.Number(10, 'px')); - list2.setValue(1, new sass.types.Number(15, 'px')); - list2.setValue(2, new sass.types.Number(32, 'px')); - list2.setSeparator(false); - map.setValue(5, list2); - // null variable - map.setKey(6, new sass.types.String('$var6')); - map.setValue(6, sass.types.Null.NULL); - - compiler.collector(map); - - expect(compiler.changedVariables).toEqual([ - { Key: '$var1', Value: '300px', Path: 'tb/path' }, - { Key: '$var2', Value: 'Helvetica', Path: 'tb/path' }, - { Key: '$var3', Value: 'rgba(50,60,70,0.4)', Path: 'tb/path' }, - { Key: '$var4', Value: '10px,15px,32px', Path: 'tb/path' }, - { Key: '$var5', Value: '10px 15px 32px', Path: 'tb/path' }, - ]); - }); - - test('getMatchingUserItemsAsString - return right string for the url', () => { - const compiler = new Compiler(); - - const testCases = [ - { - 'userItems': [{ - key: '$var2', - value: 'rgba(0,0,0,0)' - }, { - key: '$var0', - value: '10px' - }], - 'url': 'tb/path', - 'expected': '$var2: rgba(0,0,0,0);$var0: 10px;' - }, - { - 'userItems': [{ - key: '$var2', - value: 'rgba(0,0,0,0)' - }], - 'url': 'tb/path', - 'expected': '$var2: rgba(0,0,0,0);' - }, - { - 'userItems': [{ - key: '$var3', - value: 'rgba(0,0,0,0)' - }], - 'url': 'tb/path', - 'expected': '' - }, - { - 'userItems': [{ - key: '$var3', - value: 'rgba(0,0,0,0)' - }], - 'url': 'tb/another/path', - 'expected': '$var3: rgba(0,0,0,0);' - } - ]; - - testCases.forEach(testCase => { - compiler.userItems = testCase.userItems; - - const content = compiler.getMatchingUserItemsAsString(testCase.url); - - expect(content).toEqual(testCase.expected); - }); - }); - - test('setter function (custom importer)', () => { - const compiler = new Compiler(); - compiler.userItems = [{ - key: '$var2', - value: 'rgba(0,0,0,0)' - }, { - key: '$var0', - value: '10px' - }]; - - const setterResult = compiler.setter('tb/path', ''); - expect(setterResult).toEqual({ contents: '$var2: rgba(0,0,0,0);$var0: 10px;' }); - expect(compiler.importerCache).toEqual({ 'tb/path': '$var2: rgba(0,0,0,0);$var0: 10px;' }); - }); - - test('setter call getMatchingUserItemsAsString once for every url', () => { - const url = 'path1'; - const compiler = new Compiler(); - compiler.getMatchingUserItemsAsString = jest.fn().mockImplementation(() => 'content'); - compiler.setter(url, ''); - compiler.setter(url, ''); - compiler.setter(url, ''); - - expect(compiler.getMatchingUserItemsAsString).toHaveBeenCalledTimes(1); - expect(compiler.importerCache[url]).toBe('content'); + }); + + test('Compile with error', () => { + const compiler = new Compiler(); + return compiler.compile('dx.error.scss', [], null).then( + () => expect(false).toBe(true), + (error) => { + expect(error.status).toBe(3); + expect(error.formatted).toBe('Error: dx.error.scss: no such file or directory'); + }, + ); + }); + + test('Compile with custom sass compiler options (try to compile with custom data)', () => { + const compiler = new Compiler(); + const bundleContent = fs.readFileSync(bundle, 'utf8'); + const extraOptions = { + data: `${bundleContent}.extra-class { color: red; }`, + outputStyle: 'compressed' as const, + }; + return compiler.compile(bundle, [], extraOptions).then((data) => { + // compiled css + expect(data.result.css.toString()).toBe( + '.dx-accordion{background-color:' + + '"Helvetica Neue","Segoe UI",Helvetica,Verdana,sans-serif;' + + 'color:#337ab7;font:url("icons/icons.woff2")}.dx-accordion ' + + '.from-base{background-color:transparent;color:#337ab7}.extra-class{color:red}', + ); }); + }); }); diff --git a/themebuilder-scss/tests/modules/config-normalizer.test.ts b/themebuilder-scss/tests/modules/config-normalizer.test.ts index f4434478c503..afec2f09bec8 100644 --- a/themebuilder-scss/tests/modules/config-normalizer.test.ts +++ b/themebuilder-scss/tests/modules/config-normalizer.test.ts @@ -1,621 +1,627 @@ import normalizeConfig from '../../src/modules/config-normalizer'; import commands from '../../src/modules/commands'; -const reader = () => {}; +const reader = (): void => {}; +const lessCompiler: LessCompilerInterface = { + render: (): void => {}, +}; describe('Cli arguments normalizer', () => { - - test('Commands stay unchanged', () => { - let config: ConfigSettings = { command: 'build-theme' }; - normalizeConfig(config); - expect(config.command).toBe(commands.BUILD_THEME); - - config = { command: 'export-theme-vars' }; - - normalizeConfig(config); - expect(config.command).toBe(commands.BUILD_VARS); + test('Commands stay unchanged', () => { + let config: ConfigSettings = { command: 'build-theme' }; + normalizeConfig(config); + expect(config.command).toBe(commands.BUILD_THEME); + + config = { command: 'export-theme-vars' }; + + normalizeConfig(config); + expect(config.command).toBe(commands.BUILD_VARS); + }); + + test('build-theme default parameters', () => { + const config: ConfigSettings = { command: 'build-theme' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'light', + command: 'build-theme', + data: {}, + fileFormat: 'css', + isBootstrap: false, + makeSwatch: false, + out: 'dx.generic.custom-scheme.css', + outColorScheme: 'custom-scheme', + themeName: 'generic', }); - - test('build-theme default parameters', () => { - const config: ConfigSettings = { command: 'build-theme' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'light', - 'command': 'build-theme', - 'data': {}, - 'fileFormat': 'css', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'dx.generic.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'themeName': 'generic' - }); + }); + + test('export-theme-vars default parameters', () => { + const config: ConfigSettings = { command: 'export-theme-vars' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'light', + command: 'export-theme-vars', + data: {}, + fileFormat: 'less', + isBootstrap: false, + makeSwatch: false, + out: 'dx.generic.custom-scheme.less', + outColorScheme: 'custom-scheme', + themeName: 'generic', }); - - test('export-theme-vars default parameters', () => { - const config: ConfigSettings = { command: 'export-theme-vars' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'light', - 'command': 'export-theme-vars', - 'data': {}, - 'fileFormat': 'less', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'dx.generic.custom-scheme.less', - 'outColorScheme': 'custom-scheme', - 'themeName': 'generic' - }); + }); + + test('build-theme bootstrap configuration', () => { + let config: ConfigSettings = { command: 'build-theme', inputFile: 'vars.less' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 3, + colorScheme: 'light', + command: 'build-theme', + data: {}, + fileFormat: 'css', + isBootstrap: true, + makeSwatch: false, + out: 'dx.generic.custom-scheme.css', + outColorScheme: 'custom-scheme', + themeName: 'generic', }); - test('build-theme bootstrap configuration', () => { - let config: ConfigSettings = { command: 'build-theme', inputFile: 'vars.less' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 3, - 'colorScheme': 'light', - 'command': 'build-theme', - 'data': {}, - 'fileFormat': 'css', - 'isBootstrap': true, - 'makeSwatch': false, - 'out': 'dx.generic.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'themeName': 'generic' - }); - - - config = { command: 'build-theme', inputFile: 'vars.scss' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 4, - 'colorScheme': 'light', - 'command': 'build-theme', - 'data': {}, - 'fileFormat': 'css', - 'isBootstrap': true, - 'makeSwatch': false, - 'out': 'dx.generic.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'themeName': 'generic' - }); - }); - test('export-theme-vars bootstrap configuration', () => { - const config1: ConfigSettings = { command: 'export-theme-vars', inputFile: 'vars.less' }; - normalizeConfig(config1); - - expect(config1).toEqual({ - 'base': false, - 'bootstrapVersion': 3, - 'colorScheme': 'light', - 'command': 'export-theme-vars', - 'data': {}, - 'fileFormat': 'less', - 'isBootstrap': true, - 'makeSwatch': false, - 'out': 'dx.generic.custom-scheme.less', - 'outColorScheme': 'custom-scheme', - 'themeName': 'generic' - }); - - const config2: ConfigSettings = { command: 'export-theme-vars', inputFile: 'vars.scss' }; - normalizeConfig(config2); - - expect(config2).toEqual({ - 'base': false, - 'bootstrapVersion': 4, - 'colorScheme': 'light', - 'command': 'export-theme-vars', - 'data': {}, - 'fileFormat': 'less', - 'isBootstrap': true, - 'makeSwatch': false, - 'out': 'dx.generic.custom-scheme.less', - 'outColorScheme': 'custom-scheme', - 'themeName': 'generic' - }); - - const config3: ConfigSettings = { command: 'export-theme-vars', inputFile: 'vars.scss', outputFile: './dir/file.scss' }; - normalizeConfig(config3); - - expect(config3).toEqual({ - 'base': false, - 'bootstrapVersion': 4, - 'colorScheme': 'light', - 'command': 'export-theme-vars', - 'data': {}, - 'fileFormat': 'scss', - 'isBootstrap': true, - 'makeSwatch': false, - 'out': './dir/file.scss', - 'outColorScheme': 'custom-scheme', - 'themeName': 'generic' - }); + config = { command: 'build-theme', inputFile: 'vars.scss' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 4, + colorScheme: 'light', + command: 'build-theme', + data: {}, + fileFormat: 'css', + isBootstrap: true, + makeSwatch: false, + out: 'dx.generic.custom-scheme.css', + outColorScheme: 'custom-scheme', + themeName: 'generic', }); - - test('build-theme output parameters (file and color scheme)', () => { - const config: ConfigSettings = { command: 'build-theme', outputFile: './dir/file.css', outputColorScheme: 'green' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'light', - 'command': 'build-theme', - 'data': {}, - 'fileFormat': 'css', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': './dir/file.css', - 'outColorScheme': 'green', - 'themeName': 'generic' - }); + }); + + test('export-theme-vars bootstrap configuration', () => { + const config1: ConfigSettings = { command: 'export-theme-vars', inputFile: 'vars.less' }; + normalizeConfig(config1); + + expect(config1).toEqual({ + base: false, + bootstrapVersion: 3, + colorScheme: 'light', + command: 'export-theme-vars', + data: {}, + fileFormat: 'less', + isBootstrap: true, + makeSwatch: false, + out: 'dx.generic.custom-scheme.less', + outColorScheme: 'custom-scheme', + themeName: 'generic', }); - test('build-theme output parameters (color scheme only)', () => { - const config: ConfigSettings = { command: 'build-theme', outputColorScheme: 'green' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'light', - 'command': 'build-theme', - 'data': {}, - 'fileFormat': 'css', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'dx.generic.green.css', - 'outColorScheme': 'green', - 'themeName': 'generic' - }); + const config2: ConfigSettings = { command: 'export-theme-vars', inputFile: 'vars.scss' }; + normalizeConfig(config2); + + expect(config2).toEqual({ + base: false, + bootstrapVersion: 4, + colorScheme: 'light', + command: 'export-theme-vars', + data: {}, + fileFormat: 'less', + isBootstrap: true, + makeSwatch: false, + out: 'dx.generic.custom-scheme.less', + outColorScheme: 'custom-scheme', + themeName: 'generic', }); - test('build-theme output parameters (color scheme, swatch, base)', () => { - const config: ConfigSettings = { command: 'build-theme', outputColorScheme: 'green', makeSwatch: true, base: true }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': true, - 'bootstrapVersion': 0, - 'colorScheme': 'light', - 'command': 'build-theme', - 'data': {}, - 'fileFormat': 'css', - 'isBootstrap': false, - 'makeSwatch': true, - 'out': 'dx.generic.green.css', - 'outColorScheme': 'green', - 'themeName': 'generic' - }); + const config3: ConfigSettings = { command: 'export-theme-vars', inputFile: 'vars.scss', outputFile: './dir/file.scss' }; + normalizeConfig(config3); + + expect(config3).toEqual({ + base: false, + bootstrapVersion: 4, + colorScheme: 'light', + command: 'export-theme-vars', + data: {}, + fileFormat: 'scss', + isBootstrap: true, + makeSwatch: false, + out: './dir/file.scss', + outColorScheme: 'custom-scheme', + themeName: 'generic', }); - - test('build-theme output parameters (color scheme not valid)', () => { - const config: ConfigSettings = { command: 'build-theme', outputColorScheme: '$#@green' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'light', - 'command': 'build-theme', - 'data': {}, - 'fileFormat': 'css', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'dx.generic.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'themeName': 'generic' - }); + }); + + test('build-theme output parameters (file and color scheme)', () => { + const config: ConfigSettings = { command: 'build-theme', outputFile: './dir/file.css', outputColorScheme: 'green' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'light', + command: 'build-theme', + data: {}, + fileFormat: 'css', + isBootstrap: false, + makeSwatch: false, + out: './dir/file.css', + outColorScheme: 'green', + themeName: 'generic', }); - - test('export-theme-vars output parameters (color scheme)', () => { - const config: ConfigSettings = { command: 'export-theme-vars', outputColorScheme: 'green' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'light', - 'command': 'export-theme-vars', - 'data': {}, - 'fileFormat': 'less', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'dx.generic.green.less', - 'outColorScheme': 'green', - 'themeName': 'generic' - }); + }); + + test('build-theme output parameters (color scheme only)', () => { + const config: ConfigSettings = { command: 'build-theme', outputColorScheme: 'green' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'light', + command: 'build-theme', + data: {}, + fileFormat: 'css', + isBootstrap: false, + makeSwatch: false, + out: 'dx.generic.green.css', + outColorScheme: 'green', + themeName: 'generic', }); - - test('export-theme-vars output parameters (color scheme, output file: less)', () => { - const config: ConfigSettings = { command: 'export-theme-vars', outputColorScheme: 'green', outputFile: 'vars.less' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'light', - 'command': 'export-theme-vars', - 'data': {}, - 'fileFormat': 'less', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'vars.less', - 'outColorScheme': 'green', - 'themeName': 'generic' - }); + }); + + test('build-theme output parameters (color scheme, swatch, base)', () => { + const config: ConfigSettings = { + command: 'build-theme', outputColorScheme: 'green', makeSwatch: true, base: true, + }; + normalizeConfig(config); + + expect(config).toEqual({ + base: true, + bootstrapVersion: 0, + colorScheme: 'light', + command: 'build-theme', + data: {}, + fileFormat: 'css', + isBootstrap: false, + makeSwatch: true, + out: 'dx.generic.green.css', + outColorScheme: 'green', + themeName: 'generic', }); - - test('export-theme-vars output parameters (color scheme, output file: scss)', () => { - const config: ConfigSettings = { command: 'export-theme-vars', outputColorScheme: 'green', outputFile: 'vars.scss' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'light', - 'command': 'export-theme-vars', - 'data': {}, - 'fileFormat': 'scss', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'vars.scss', - 'outColorScheme': 'green', - 'themeName': 'generic' - }); + }); + + test('build-theme output parameters (color scheme not valid)', () => { + const config: ConfigSettings = { command: 'build-theme', outputColorScheme: '$#@green' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'light', + command: 'build-theme', + data: {}, + fileFormat: 'css', + isBootstrap: false, + makeSwatch: false, + out: 'dx.generic.custom-scheme.css', + outColorScheme: 'custom-scheme', + themeName: 'generic', }); - - test('export-theme-vars output parameters (color scheme, output file: scss, file format: less) (wrong file format - file extension pair)', () => { - const config: ConfigSettings = { command: 'export-theme-vars', outputColorScheme: 'green', outputFile: 'vars.scss', outputFormat: 'less' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'light', - 'command': 'export-theme-vars', - 'data': {}, - 'fileFormat': 'less', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'vars.scss', - 'outColorScheme': 'green', - 'themeName': 'generic' - }); + }); + + test('export-theme-vars output parameters (color scheme)', () => { + const config: ConfigSettings = { command: 'export-theme-vars', outputColorScheme: 'green' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'light', + command: 'export-theme-vars', + data: {}, + fileFormat: 'less', + isBootstrap: false, + makeSwatch: false, + out: 'dx.generic.green.less', + outColorScheme: 'green', + themeName: 'generic', }); - - test('export-theme-vars output parameters (color scheme, output file: scss, file format: scss)', () => { - const config: ConfigSettings = { command: 'export-theme-vars', outputColorScheme: 'green', outputFormat: 'scss' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'light', - 'command': 'export-theme-vars', - 'data': {}, - 'fileFormat': 'scss', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'dx.generic.green.scss', - 'outColorScheme': 'green', - 'themeName': 'generic' - }); + }); + + test('export-theme-vars output parameters (color scheme, output file: less)', () => { + const config: ConfigSettings = { command: 'export-theme-vars', outputColorScheme: 'green', outputFile: 'vars.less' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'light', + command: 'export-theme-vars', + data: {}, + fileFormat: 'less', + isBootstrap: false, + makeSwatch: false, + out: 'vars.less', + outColorScheme: 'green', + themeName: 'generic', }); - - test('build-theme input parameters (base theme)', () => { - const config: ConfigSettings = { command: 'build-theme', baseTheme: 'material.blue.light' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'blue-light', - 'command': 'build-theme', - 'data': {}, - 'fileFormat': 'css', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'dx.material.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'themeName': 'material' - }); + }); + + test('export-theme-vars output parameters (color scheme, output file: scss)', () => { + const config: ConfigSettings = { command: 'export-theme-vars', outputColorScheme: 'green', outputFile: 'vars.scss' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'light', + command: 'export-theme-vars', + data: {}, + fileFormat: 'scss', + isBootstrap: false, + makeSwatch: false, + out: 'vars.scss', + outColorScheme: 'green', + themeName: 'generic', }); - - test('build-theme input parameters (base theme) - material compact', () => { - const config: ConfigSettings = { command: 'build-theme', baseTheme: 'material.blue.light.compact' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'blue-light-compact', - 'command': 'build-theme', - 'data': {}, - 'fileFormat': 'css', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'dx.material.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'themeName': 'material' - }); + }); + + test('export-theme-vars output parameters (color scheme, output file: scss, file format: less) (wrong file format - file extension pair)', () => { + const config: ConfigSettings = { + command: 'export-theme-vars', outputColorScheme: 'green', outputFile: 'vars.scss', outputFormat: 'less', + }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'light', + command: 'export-theme-vars', + data: {}, + fileFormat: 'less', + isBootstrap: false, + makeSwatch: false, + out: 'vars.scss', + outColorScheme: 'green', + themeName: 'generic', }); - - test('build-theme input parameters (base theme, input file)', () => { - const config: ConfigSettings = { command: 'build-theme', baseTheme: 'material.blue.light', inputFile: 'file.json' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'blue-light', - 'command': 'build-theme', - 'data': {}, - 'fileFormat': 'css', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'dx.material.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'themeName': 'material' - }); + }); + + test('export-theme-vars output parameters (color scheme, output file: scss, file format: scss)', () => { + const config: ConfigSettings = { command: 'export-theme-vars', outputColorScheme: 'green', outputFormat: 'scss' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'light', + command: 'export-theme-vars', + data: {}, + fileFormat: 'scss', + isBootstrap: false, + makeSwatch: false, + out: 'dx.generic.green.scss', + outColorScheme: 'green', + themeName: 'generic', }); - - test('build-theme \'data\', \'items\', \'reader\', \'lessCompiler\' stay unchanged', () => { - const config: ConfigSettings = { - command: 'build-theme', - baseTheme: 'material.blue.light', - inputFile: 'file.json', - data: 'somedata', - items: [{ key: '1', value: '2' }], - reader: reader, - lessCompiler: 'l' - }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'blue-light', - 'command': 'build-theme', - 'data': 'somedata', - 'fileFormat': 'css', - 'isBootstrap': false, - 'items': [{ key: '1', value: '2' }], - 'lessCompiler': 'l', - 'makeSwatch': false, - 'out': 'dx.material.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'reader': reader, - 'themeName': 'material' - }); + }); + + test('build-theme input parameters (base theme)', () => { + const config: ConfigSettings = { command: 'build-theme', baseTheme: 'material.blue.light' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'blue-light', + command: 'build-theme', + data: {}, + fileFormat: 'css', + isBootstrap: false, + makeSwatch: false, + out: 'dx.material.custom-scheme.css', + outColorScheme: 'custom-scheme', + themeName: 'material', }); - - test('build-theme: if \'data\' is empty string it will be unchanged', () => { - const config: ConfigSettings = { - command: 'build-theme', - baseTheme: 'material.blue.light', - data: '', - items: [{ key: '', value: '' }], - reader: reader, - lessCompiler: 'l' - }; - - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'blue-light', - 'command': 'build-theme', - 'data': '', - 'fileFormat': 'css', - 'isBootstrap': false, - 'items': [{ key: '', value: '' }], - 'lessCompiler': 'l', - 'makeSwatch': false, - 'out': 'dx.material.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'reader': reader, - 'themeName': 'material' - }); + }); + + test('build-theme input parameters (base theme) - material compact', () => { + const config: ConfigSettings = { command: 'build-theme', baseTheme: 'material.blue.light.compact' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'blue-light-compact', + command: 'build-theme', + data: {}, + fileFormat: 'css', + isBootstrap: false, + makeSwatch: false, + out: 'dx.material.custom-scheme.css', + outColorScheme: 'custom-scheme', + themeName: 'material', }); - - test('build-theme: if themeId is set, but baseTheme not - right theme will be set', () => { - const config: ConfigSettings = { command: 'build-theme', themeId: 27 }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'teal-light', - 'command': 'build-theme', - 'data': {}, - 'fileFormat': 'css', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'dx.material.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'themeName': 'material' - }); + }); + + test('build-theme input parameters (base theme, input file)', () => { + const config: ConfigSettings = { command: 'build-theme', baseTheme: 'material.blue.light', inputFile: 'file.json' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'blue-light', + command: 'build-theme', + data: {}, + fileFormat: 'css', + isBootstrap: false, + makeSwatch: false, + out: 'dx.material.custom-scheme.css', + outColorScheme: 'custom-scheme', + themeName: 'material', }); - - test('build-theme: if themeId and baseTheme both are set - themeId will be ignored', () => { - const config: ConfigSettings = { command: 'build-theme', themeId: 27, baseTheme: 'material.blue.light' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'blue-light', - 'command': 'build-theme', - 'data': {}, - 'fileFormat': 'css', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'dx.material.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'themeName': 'material' - }); + }); + + test('build-theme \'data\', \'items\', \'reader\', \'lessCompiler\' stay unchanged', () => { + const config: ConfigSettings = { + command: 'build-theme', + baseTheme: 'material.blue.light', + inputFile: 'file.json', + data: 'somedata', + items: [{ key: '1', value: '2' }], + reader, + lessCompiler, + }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'blue-light', + command: 'build-theme', + data: 'somedata', + fileFormat: 'css', + isBootstrap: false, + items: [{ key: '1', value: '2' }], + lessCompiler, + makeSwatch: false, + out: 'dx.material.custom-scheme.css', + outColorScheme: 'custom-scheme', + reader, + themeName: 'material', }); - - test('build-theme: if themeId is wrong, generic.light will be used', () => { - const config: ConfigSettings = { command: 'build-theme', themeId: 270 }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'light', - 'command': 'build-theme', - 'data': {}, - 'fileFormat': 'css', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'dx.generic.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'themeName': 'generic' - }); + }); + + test('build-theme: if \'data\' is empty string it will be unchanged', () => { + const config: ConfigSettings = { + command: 'build-theme', + baseTheme: 'material.blue.light', + data: '', + items: [{ key: '', value: '' }], + reader, + lessCompiler, + }; + + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'blue-light', + command: 'build-theme', + data: '', + fileFormat: 'css', + isBootstrap: false, + items: [{ key: '', value: '' }], + lessCompiler, + makeSwatch: false, + out: 'dx.material.custom-scheme.css', + outColorScheme: 'custom-scheme', + reader, + themeName: 'material', }); - - test('build-theme: if baseTheme is wrong, generic.light will be used', () => { - const config: ConfigSettings = { command: 'build-theme', baseTheme: 'wrong.theme' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'light', - 'command': 'build-theme', - 'data': {}, - 'fileFormat': 'css', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'dx.generic.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'themeName': 'generic' - }); + }); + + test('build-theme: if themeId is set, but baseTheme not - right theme will be set', () => { + const config: ConfigSettings = { command: 'build-theme', themeId: 27 }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'teal-light', + command: 'build-theme', + data: {}, + fileFormat: 'css', + isBootstrap: false, + makeSwatch: false, + out: 'dx.material.custom-scheme.css', + outColorScheme: 'custom-scheme', + themeName: 'material', }); - - test('export-theme-meta: default file format - json', () => { - const config: ConfigSettings = { command: 'export-theme-meta' }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'light', - 'command': 'export-theme-meta', - 'data': {}, - 'fileFormat': 'json', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'dx.generic.custom-scheme.json', - 'outColorScheme': 'custom-scheme', - 'themeName': 'generic' - }); + }); + + test('build-theme: if themeId and baseTheme both are set - themeId will be ignored', () => { + const config: ConfigSettings = { command: 'build-theme', themeId: 27, baseTheme: 'material.blue.light' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'blue-light', + command: 'build-theme', + data: {}, + fileFormat: 'css', + isBootstrap: false, + makeSwatch: false, + out: 'dx.material.custom-scheme.css', + outColorScheme: 'custom-scheme', + themeName: 'material', }); - - test('Paths are always normalized', () => { - let config = { lessPath: 'my/custom/less', scssPath: 'my/custom/scss' }; - normalizeConfig(config); - expect(config.lessPath).toBe('my/custom/less/'); - expect(config.scssPath).toBe('my/custom/scss/'); - - config = { lessPath: 'my/custom/less/', scssPath: 'my/custom/scss/' }; - normalizeConfig(config); - expect(config.lessPath).toBe('my/custom/less/'); - expect(config.scssPath).toBe('my/custom/scss/'); + }); + + test('build-theme: if themeId is wrong, generic.light will be used', () => { + const config: ConfigSettings = { command: 'build-theme', themeId: 270 }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'light', + command: 'build-theme', + data: {}, + fileFormat: 'css', + isBootstrap: false, + makeSwatch: false, + out: 'dx.generic.custom-scheme.css', + outColorScheme: 'custom-scheme', + themeName: 'generic', }); - - test('build-theme: \'widgets\' field is normalized', () => { - const config: ConfigSettings = { command: 'build-theme', widgets: ['datagrid'] }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'light', - 'command': 'build-theme', - 'data': {}, - 'fileFormat': 'css', - 'isBootstrap': false, - 'makeSwatch': false, - 'out': 'dx.generic.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'themeName': 'generic', - 'widgets': ['datagrid'] - }); + }); + + test('build-theme: if baseTheme is wrong, generic.light will be used', () => { + const config: ConfigSettings = { command: 'build-theme', baseTheme: 'wrong.theme' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'light', + command: 'build-theme', + data: {}, + fileFormat: 'css', + isBootstrap: false, + makeSwatch: false, + out: 'dx.generic.custom-scheme.css', + outColorScheme: 'custom-scheme', + themeName: 'generic', }); - - test('build-theme @treelist constants change to the @datagrid constants', () => { - const config: ConfigSettings = { - command: 'build-theme', - baseTheme: 'material.blue.light', - inputFile: 'file.json', - data: 'somedata', - items: [{ key: '1', value: '2' }, { key: '@treelist-bg-color', value: '2' }, { key: '@treelist-border-color', value: '3' }], - reader: reader, - lessCompiler: 'l' - }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'blue-light', - 'command': 'build-theme', - 'data': 'somedata', - 'fileFormat': 'css', - 'isBootstrap': false, - 'items': [{ key: '1', value: '2' }, { key: '$datagrid-bg-color', value: '2' }, { key: '$datagrid-border-color', value: '3' }], - 'lessCompiler': 'l', - 'makeSwatch': false, - 'out': 'dx.material.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'reader': reader, - 'themeName': 'material' - }); + }); + + test('export-theme-meta: default file format - json', () => { + const config: ConfigSettings = { command: 'export-theme-meta' }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'light', + command: 'export-theme-meta', + data: {}, + fileFormat: 'json', + isBootstrap: false, + makeSwatch: false, + out: 'dx.generic.custom-scheme.json', + outColorScheme: 'custom-scheme', + themeName: 'generic', }); - - test('"@" is replaced with "$" in the "key" field in items', () => { - const config: ConfigSettings = { - command: 'build-theme', - baseTheme: 'material.blue.light', - inputFile: 'file.json', - data: 'somedata', - items: [{ key: '@datagrid-bg-color', value: '2' }, { key: '@datagrid-border-color', value: '3' }], - reader: reader, - lessCompiler: 'l' - }; - normalizeConfig(config); - - expect(config).toEqual({ - 'base': false, - 'bootstrapVersion': 0, - 'colorScheme': 'blue-light', - 'command': 'build-theme', - 'data': 'somedata', - 'fileFormat': 'css', - 'isBootstrap': false, - 'items': [{ key: '$datagrid-bg-color', value: '2' }, { key: '$datagrid-border-color', value: '3' }], - 'lessCompiler': 'l', - 'makeSwatch': false, - 'out': 'dx.material.custom-scheme.css', - 'outColorScheme': 'custom-scheme', - 'reader': reader, - 'themeName': 'material' - }); + }); + + test('Paths are always normalized', () => { + let config = { lessPath: 'my/custom/less', scssPath: 'my/custom/scss' }; + normalizeConfig(config); + expect(config.lessPath).toBe('my/custom/less/'); + expect(config.scssPath).toBe('my/custom/scss/'); + + config = { lessPath: 'my/custom/less/', scssPath: 'my/custom/scss/' }; + normalizeConfig(config); + expect(config.lessPath).toBe('my/custom/less/'); + expect(config.scssPath).toBe('my/custom/scss/'); + }); + + test('build-theme: \'widgets\' field is normalized', () => { + const config: ConfigSettings = { command: 'build-theme', widgets: ['datagrid'] }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'light', + command: 'build-theme', + data: {}, + fileFormat: 'css', + isBootstrap: false, + makeSwatch: false, + out: 'dx.generic.custom-scheme.css', + outColorScheme: 'custom-scheme', + themeName: 'generic', + widgets: ['datagrid'], + }); + }); + + test('build-theme @treelist constants change to the @datagrid constants', () => { + const config: ConfigSettings = { + command: 'build-theme', + baseTheme: 'material.blue.light', + inputFile: 'file.json', + data: 'somedata', + items: [{ key: '1', value: '2' }, { key: '@treelist-bg-color', value: '2' }, { key: '@treelist-border-color', value: '3' }], + reader, + lessCompiler, + }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'blue-light', + command: 'build-theme', + data: 'somedata', + fileFormat: 'css', + isBootstrap: false, + items: [{ key: '1', value: '2' }, { key: '$datagrid-bg-color', value: '2' }, { key: '$datagrid-border-color', value: '3' }], + lessCompiler, + makeSwatch: false, + out: 'dx.material.custom-scheme.css', + outColorScheme: 'custom-scheme', + reader, + themeName: 'material', + }); + }); + + test('"@" is replaced with "$" in the "key" field in items', () => { + const config: ConfigSettings = { + command: 'build-theme', + baseTheme: 'material.blue.light', + inputFile: 'file.json', + data: 'somedata', + items: [{ key: '@datagrid-bg-color', value: '2' }, { key: '@datagrid-border-color', value: '3' }], + reader, + lessCompiler, + }; + normalizeConfig(config); + + expect(config).toEqual({ + base: false, + bootstrapVersion: 0, + colorScheme: 'blue-light', + command: 'build-theme', + data: 'somedata', + fileFormat: 'css', + isBootstrap: false, + items: [{ key: '$datagrid-bg-color', value: '2' }, { key: '$datagrid-border-color', value: '3' }], + lessCompiler, + makeSwatch: false, + out: 'dx.material.custom-scheme.css', + outColorScheme: 'custom-scheme', + reader, + themeName: 'material', }); + }); }); diff --git a/themebuilder-scss/tests/modules/post-compiler.test.ts b/themebuilder-scss/tests/modules/post-compiler.test.ts index 81566e21f870..0c1912076b14 100644 --- a/themebuilder-scss/tests/modules/post-compiler.test.ts +++ b/themebuilder-scss/tests/modules/post-compiler.test.ts @@ -1,21 +1,19 @@ -import { PostCompiler } from '../../src/modules/post-compiler'; +import PostCompiler from '../../src/modules/post-compiler'; describe('PostCompiler', () => { - test('addBasePath', () => { - const postCompiler = new PostCompiler(); + test('addBasePath', () => { + expect(PostCompiler.addBasePath('font: url(fonts/roboto.ttf);', 'base')).toBe('font: url(base/fonts/roboto.ttf);'); + expect(PostCompiler.addBasePath('font: url(fonts/roboto.ttf);', 'base/')).toBe('font: url(base/fonts/roboto.ttf);'); + expect(PostCompiler.addBasePath('font: url(fonts/roboto.ttf);', 'c:\\base\\')).toBe('font: url(c:\\base/fonts/roboto.ttf);'); - expect(postCompiler.addBasePath('font: url(fonts/roboto.ttf);', 'base')).toBe('font: url(base/fonts/roboto.ttf);'); - expect(postCompiler.addBasePath('font: url(fonts/roboto.ttf);', 'base/')).toBe('font: url(base/fonts/roboto.ttf);'); - expect(postCompiler.addBasePath('font: url(fonts/roboto.ttf);', 'c:\\base\\')).toBe('font: url(c:\\base/fonts/roboto.ttf);'); + expect(PostCompiler.addBasePath('font: url(fonts/r.ttf),url(fonts/r.woff);', 'base/')).toBe('font: url(base/fonts/r.ttf),url(base/fonts/r.woff);'); + expect(PostCompiler.addBasePath('font: url(\'fonts/roboto.ttf\');', 'base/')).toBe('font: url(\'base/fonts/roboto.ttf\');'); + expect(PostCompiler.addBasePath('font: url("fonts/roboto.ttf");', 'base/')).toBe('font: url("base/fonts/roboto.ttf");'); - expect(postCompiler.addBasePath('font: url(fonts/r.ttf),url(fonts/r.woff);', 'base/')).toBe('font: url(base/fonts/r.ttf),url(base/fonts/r.woff);'); - expect(postCompiler.addBasePath('font: url(\'fonts/roboto.ttf\');', 'base/')).toBe('font: url(\'base/fonts/roboto.ttf\');'); - expect(postCompiler.addBasePath('font: url("fonts/roboto.ttf");', 'base/')).toBe('font: url("base/fonts/roboto.ttf");'); + expect(PostCompiler.addBasePath('font: url(icons/roboto.ttf);', 'base/')).toBe('font: url(base/icons/roboto.ttf);'); + expect(PostCompiler.addBasePath(Buffer.from('font: url(icons/roboto.ttf);'), 'base/')).toBe('font: url(base/icons/roboto.ttf);'); - expect(postCompiler.addBasePath('font: url(icons/roboto.ttf);', 'base/')).toBe('font: url(base/icons/roboto.ttf);'); - expect(postCompiler.addBasePath(Buffer.from('font: url(icons/roboto.ttf);'), 'base/')).toBe('font: url(base/icons/roboto.ttf);'); - - expect(postCompiler.addBasePath('font: url(data:BASE64);', 'base/')).toBe('font: url(data:BASE64);'); - expect(postCompiler.addBasePath('font: url(image SVG);', 'base/')).toBe('font: url(image SVG);'); - }); -}); \ No newline at end of file + expect(PostCompiler.addBasePath('font: url(data:BASE64);', 'base/')).toBe('font: url(data:BASE64);'); + expect(PostCompiler.addBasePath('font: url(image SVG);', 'base/')).toBe('font: url(image SVG);'); + }); +}); diff --git a/themebuilder-scss/tests/modules/pre-compiler.test.ts b/themebuilder-scss/tests/modules/pre-compiler.test.ts index fb5247c84b29..0331995ff869 100644 --- a/themebuilder-scss/tests/modules/pre-compiler.test.ts +++ b/themebuilder-scss/tests/modules/pre-compiler.test.ts @@ -1,9 +1,8 @@ -import { PreCompiler } from '../../src/modules/pre-compiler'; +import PreCompiler from '../../src/modules/pre-compiler'; describe('PreCompiler class tests', () => { - test('createSassForSwatch', () => { - const preCompiler = new PreCompiler(); - expect(preCompiler.createSassForSwatch('test-theme-name', 'sass')).toBe('.dx-swatch-test-theme-name { sass };'); - }); + test('createSassForSwatch', () => { + expect(PreCompiler.createSassForSwatch('test-theme-name', 'sass')).toBe('.dx-swatch-test-theme-name { sass };'); + }); }); diff --git a/themebuilder-scss/tsconfig.json b/themebuilder-scss/tsconfig.json index 43c2bb104366..9a79a75ca99f 100644 --- a/themebuilder-scss/tsconfig.json +++ b/themebuilder-scss/tsconfig.json @@ -21,7 +21,8 @@ }, "include": [ "src/modules/*", - "src/data/*", - "src/types/*" + "src/data/**/*", + "src/types/*", + "src/metadata/*" ] } From c7b127171027b6b4b4f7da70afdf1db6a7cf4dfa Mon Sep 17 00:00:00 2001 From: babich-a Date: Thu, 14 May 2020 17:24:00 +0300 Subject: [PATCH 2/7] try to ignore themebuilder-scss in global linter --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 72bfd2f6d8b8..29d21e1cfbd4 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ }, "scripts": { "lint": "npm-run-all -p -c lint-js lint-css", - "lint-js": "eslint .", + "lint-js": "eslint --ignore-pattern themebuilder-scss/**/* .", "lint-css": "stylelint styles", "lint-staged": "lint-staged", "build": "dotnet build build/build-dotnet.sln && gulp default", From 805bc2cc6cc8c3696a110104233420e5cf65aa11 Mon Sep 17 00:00:00 2001 From: babich-a Date: Thu, 14 May 2020 17:37:18 +0300 Subject: [PATCH 3/7] build ts in test --- docker-ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-ci.sh b/docker-ci.sh index abba72be200b..d3d483eacd2f 100755 --- a/docker-ci.sh +++ b/docker-ci.sh @@ -195,7 +195,7 @@ function run_test_scss { node build/gulp/scss/tests/identical.test.js cd themebuilder-scss - npm i && npm run test + npm i && npm run build && npm run test } function start_runner_watchdog { From e65b75728760d22742849976effd4d3344112813 Mon Sep 17 00:00:00 2001 From: babich-a Date: Thu, 14 May 2020 20:51:53 +0300 Subject: [PATCH 4/7] fix platform-specific tests --- themebuilder-scss/tests/metadata/collector.test.ts | 8 ++++++-- themebuilder-scss/tests/metadata/generator.test.ts | 13 +++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/themebuilder-scss/tests/metadata/collector.test.ts b/themebuilder-scss/tests/metadata/collector.test.ts index 614d21a4b71e..58bd4f7df415 100644 --- a/themebuilder-scss/tests/metadata/collector.test.ts +++ b/themebuilder-scss/tests/metadata/collector.test.ts @@ -27,8 +27,11 @@ describe('MetadataCollector', () => { test('getFileList', async () => { const collector = new MetadataCollector(); const fileList = await collector.getFileList(join(rootDir, 'tests', 'data', 'scss')); + const expectedFullPaths = expectedFileList.map((file) => join(scssDir, file)); - expect(fileList).toEqual(expectedFileList.map((file) => join(scssDir, file))); + expect(fileList.length).toBe(expectedFullPaths.length); + + fileList.forEach((file) => expect(expectedFullPaths).toContain(file)); }); test('readFiles', async () => { @@ -36,9 +39,10 @@ describe('MetadataCollector', () => { const handler = (content: string): string => content; const filesInfo = await collector.readFiles(join(rootDir, 'tests', 'data', 'scss'), handler); - expect(filesInfo.map((file) => file.path)).toEqual(expectedFileList); + expect(filesInfo.length).toBe(expectedFileList.length); filesInfo.forEach((file) => { + expect(expectedFileList).toContain(file.path); expect(typeof file.content).toBe('string'); expect(file.content.length).toBeGreaterThan(0); }); diff --git a/themebuilder-scss/tests/metadata/generator.test.ts b/themebuilder-scss/tests/metadata/generator.test.ts index d29937f4431a..a24cb3b285e7 100644 --- a/themebuilder-scss/tests/metadata/generator.test.ts +++ b/themebuilder-scss/tests/metadata/generator.test.ts @@ -160,6 +160,8 @@ describe('Metadata generator - normalizePath', () => { expected: string; } + const isWin = process.platform === 'win32'; + const matrix: Array = [ { scssPath: '/scss', path: '/scss/widgets/generic/toolbar/_colors.scss', expected: 'tb/widgets/generic/toolbar/colors' }, { scssPath: '/scss', path: '/scss/widgets/generic/navBar/_colors.scss', expected: 'tb/widgets/generic/navBar/colors' }, @@ -167,10 +169,17 @@ describe('Metadata generator - normalizePath', () => { { scssPath: '/repo/scss', path: '/repo/scss/widgets/generic/toolbar/_sizes.scss', expected: 'tb/widgets/generic/toolbar/sizes' }, { scssPath: '/repo/../scss', path: '/scss/widgets/generic/toolbar/_sizes.scss', expected: 'tb/widgets/generic/toolbar/sizes' }, { scssPath: '/repo/../scss', path: '/repo/../scss/widgets/generic/toolbar/_sizes.scss', expected: 'tb/widgets/generic/toolbar/sizes' }, - { scssPath: 'd:\\repo\\scss', path: 'd:\\repo\\scss\\widgets\\generic\\toolbar\\_colors.scss', expected: 'tb/widgets/generic/toolbar/colors' }, - { scssPath: 'd:\\repo\\scss', path: 'd:\\repo\\scss\\widgets\\generic\\toolbar\\_colors.scss', expected: 'tb/widgets/generic/toolbar/colors' }, ]; + if (isWin) { + const additionalWindowsPaths: Array = [ + { scssPath: 'd:\\repo\\scss', path: 'd:\\repo\\scss\\widgets\\generic\\toolbar\\_colors.scss', expected: 'tb/widgets/generic/toolbar/colors' }, + { scssPath: 'd:\\repo\\scss', path: 'd:\\repo\\scss\\widgets\\generic\\toolbar\\_colors.scss', expected: 'tb/widgets/generic/toolbar/colors' }, + ]; + + matrix.push(...additionalWindowsPaths); + } + test('normalizePath works as expected', () => { matrix.forEach((item) => { expect(MetadataGenerator.normalizePath(item.scssPath, item.path)).toBe(item.expected); From 963443f224fe432c3c69190d828af777fb609d53 Mon Sep 17 00:00:00 2001 From: babich-a Date: Thu, 14 May 2020 21:49:14 +0300 Subject: [PATCH 5/7] fix 'big brother' linter --- .eslintignore | 4 ++-- package.json | 2 +- .../{.eslintrc => .eslintrc-themebuilder} | 12 ++++++++++++ themebuilder-scss/package.json | 2 +- themebuilder-scss/tests/.eslintrc | 8 -------- 5 files changed, 16 insertions(+), 12 deletions(-) rename themebuilder-scss/{.eslintrc => .eslintrc-themebuilder} (55%) delete mode 100644 themebuilder-scss/tests/.eslintrc diff --git a/.eslintignore b/.eslintignore index c7d8e8486646..22face29318a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,5 +2,5 @@ artifacts/* js/viz/docs/* node_modules/* testing/helpers/sinon/* -/themebuilder/data/metadata/* -/themebuilder-scss/* +themebuilder/data/metadata/* +themebuilder-scss/**/* diff --git a/package.json b/package.json index 29d21e1cfbd4..72bfd2f6d8b8 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ }, "scripts": { "lint": "npm-run-all -p -c lint-js lint-css", - "lint-js": "eslint --ignore-pattern themebuilder-scss/**/* .", + "lint-js": "eslint .", "lint-css": "stylelint styles", "lint-staged": "lint-staged", "build": "dotnet build build/build-dotnet.sln && gulp default", diff --git a/themebuilder-scss/.eslintrc b/themebuilder-scss/.eslintrc-themebuilder similarity index 55% rename from themebuilder-scss/.eslintrc rename to themebuilder-scss/.eslintrc-themebuilder index 97cf24b9972d..76975c9e985e 100644 --- a/themebuilder-scss/.eslintrc +++ b/themebuilder-scss/.eslintrc-themebuilder @@ -1,4 +1,5 @@ { + "root": true, "env": { "es6": true, "node": true @@ -14,5 +15,16 @@ }, "extends": [ "devextreme/typescript" + ], + "overrides": [ + { + "files": ["tests/**/*.ts"], + "extends": [ + "devextreme/jest" + ], + "parserOptions": { + "project": "tests/tsconfig.json" + } + } ] } \ No newline at end of file diff --git a/themebuilder-scss/package.json b/themebuilder-scss/package.json index 9a985076922a..2c1618eed1be 100644 --- a/themebuilder-scss/package.json +++ b/themebuilder-scss/package.json @@ -20,7 +20,7 @@ }, "scripts": { "test-code": "jest --coverage --verbose --detectOpenHandles", - "lint": "eslint .", + "lint": "eslint --config .eslintrc-themebuilder .", "test": "npm run lint && npm run test-code", "clean-metadata": "", "generate-metadata": "ts-node --files=true src/metadata/generate.ts", diff --git a/themebuilder-scss/tests/.eslintrc b/themebuilder-scss/tests/.eslintrc deleted file mode 100644 index c797ba88dbf9..000000000000 --- a/themebuilder-scss/tests/.eslintrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": [ - "devextreme/jest" - ], - "parserOptions": { - "project": "tests/tsconfig.json" - } -} \ No newline at end of file From 2285b695bb79152781baef97b22db4c5ec17d704 Mon Sep 17 00:00:00 2001 From: babich-a Date: Thu, 14 May 2020 22:19:23 +0300 Subject: [PATCH 6/7] small fixes --- themebuilder-scss/.eslintignore | 2 +- themebuilder-scss/.eslintrc-themebuilder | 3 +-- themebuilder-scss/src/metadata/collector.ts | 2 +- themebuilder-scss/tests/metadata/collector.test.ts | 5 ++++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/themebuilder-scss/.eslintignore b/themebuilder-scss/.eslintignore index 331869f41286..d2cd9296898c 100644 --- a/themebuilder-scss/.eslintignore +++ b/themebuilder-scss/.eslintignore @@ -2,4 +2,4 @@ coverage dist node_modules src/data/metadata/* -jest.config.js \ No newline at end of file +jest.config.js diff --git a/themebuilder-scss/.eslintrc-themebuilder b/themebuilder-scss/.eslintrc-themebuilder index 76975c9e985e..24bb24fc54b4 100644 --- a/themebuilder-scss/.eslintrc-themebuilder +++ b/themebuilder-scss/.eslintrc-themebuilder @@ -1,5 +1,4 @@ { - "root": true, "env": { "es6": true, "node": true @@ -27,4 +26,4 @@ } } ] -} \ No newline at end of file +} diff --git a/themebuilder-scss/src/metadata/collector.ts b/themebuilder-scss/src/metadata/collector.ts index b8a3c42a0498..0b3f3dd8e45b 100644 --- a/themebuilder-scss/src/metadata/collector.ts +++ b/themebuilder-scss/src/metadata/collector.ts @@ -45,7 +45,7 @@ export default class MetadataCollector { const metadata = this.generator.getMetadata(); const metaString = JSON.stringify(metadata) .replace(/"/g, '\'') - .replace(/'(ON|OFF)'/g, '"$1"'); // TODO test it! + .replace(/'(ON|OFF)'/g, '"$1"'); let metaContent = `export const metadata: Array = ${metaString};\n`; metaContent += `export const version: string = '${version}';\n`; await fs.mkdir(dirname(absolutePath), { recursive: true }); diff --git a/themebuilder-scss/tests/metadata/collector.test.ts b/themebuilder-scss/tests/metadata/collector.test.ts index 58bd4f7df415..eb0ca064e185 100644 --- a/themebuilder-scss/tests/metadata/collector.test.ts +++ b/themebuilder-scss/tests/metadata/collector.test.ts @@ -81,7 +81,10 @@ describe('MetadataCollector', () => { const fileName = join('metadata', 'dx-theme-builder-metadata.ts'); const expectedFileName = resolve(fileName); const expectedDirName = dirname(expectedFileName); - let metaContent = `export const metadata: Array = ${JSON.stringify([])};\n`; + + collector.generator.metadata = [{ Key: '$var', Value: '\'ON\'' }]; + + let metaContent = 'export const metadata: Array = [{\'Key\':\'$var\',\'Value\':\'"ON"\'}];\n'; metaContent += `export const version: string = '${version}';\n`; await collector.saveMetadata(fileName, version); From b0c72165132c468ce5923ec11d95641e718be011 Mon Sep 17 00:00:00 2001 From: Alexey Babich Date: Wed, 20 May 2020 11:48:47 +0300 Subject: [PATCH 7/7] Update themebuilder-scss/.eslintignore Co-authored-by: Alexander Ziborov <1420883+San4es@users.noreply.github.com> --- themebuilder-scss/.eslintignore | 1 - 1 file changed, 1 deletion(-) diff --git a/themebuilder-scss/.eslintignore b/themebuilder-scss/.eslintignore index d2cd9296898c..bb79b1a4e5fc 100644 --- a/themebuilder-scss/.eslintignore +++ b/themebuilder-scss/.eslintignore @@ -1,5 +1,4 @@ coverage dist -node_modules src/data/metadata/* jest.config.js