diff --git a/.babelrc b/.babelrc index 07eae76cb..31361e384 100644 --- a/.babelrc +++ b/.babelrc @@ -5,19 +5,22 @@ "@babel/preset-react" ], "plugins": [ - ["@babel/plugin-proposal-decorators", { - "legacy": true - }], - ["@babel/plugin-proposal-class-properties", { - "loose": true - }] + ["@babel/plugin-proposal-decorators", { "legacy": true }], + ["@babel/plugin-proposal-class-properties", { "loose": true }], + ["@babel/plugin-proposal-private-methods", { "loose": true }] ], "env": { + "production": { + "compact": true, + "comments": false, + "minified": true + }, "test": { "plugins": [ ["istanbul", { "exclude": [ - "tests/**/*.test.js" + // exclude from karma reporter + "tests/**/*" ] }] ] diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..6f94c907e --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,173 @@ +module.exports = { + "env": { + "browser": true, + "es6": true, + "mocha": true, + "jest": true, + "node": true + }, + "ignorePatterns": [ + "**/ts_out/*", + "**/build/*", + "**/node_modules/*", + "bundle.js", + "webpack.config.js" + ], + "extends": [ + "eslint:recommended", + "plugin:import/recommended", + "plugin:import/typescript", + "plugin:react/recommended", + "plugin:@typescript-eslint/eslint-recommended", + ], + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaVersion": 11, + "ecmaFeatures": { + "legacyDecorators": true, + "jsx": true + }, + "sourceType": "module" + }, + "plugins": [ + "react", + "babel", + "import", + "@typescript-eslint" + ], + "settings": { + "react": { + "version": "detect" + }, + "import/resolver": { + "webpack": { + "config": "./webpack.config.js" + } + }, + "import/extensions": [ + ".js", + ".jsx", + ".ts", + ".tsx" + ], + "import/parsers": { + "@typescript-eslint/parser": [ + ".ts", + ".tsx" + ] + }, + "import/core-modules": [ + "react-awesome-query-builder/lib/css/styles.css" + ] + }, + "parser": "@typescript-eslint/parser", + "rules": { + "indent": [ + "error", + 2, + { + } + ], + "linebreak-style": [ + "error", + "unix" + ], + "operator-linebreak": [ + "warn", + "before" + ], + "quotes": [ + "warn", + "double", + { + "avoidEscape": true + } + ], + "semi": [ + "error", + "always" + ], + "no-tabs": [ + "error", + { + "allowIndentationTabs": false + } + ], + "no-unused-vars": [ + //todo: set to warn + "off", + { + "args": "all", + "argsIgnorePattern": "^_", + "ignoreRestSiblings": true, + "caughtErrors": "none", + "varsIgnorePattern": "^_" + } + ], + "react/display-name": [ + "off" + ], + "global-require": [ + "off" + ], + "react/prop-types": [ + //todo: set to warn + "off", {} + ], + "prefer-const": [ + //todo: set to warn + "off", {} + ] + }, + "overrides": [ + { + "files": ["modules/**/*.ts", "modules/**/*.tsx"], + "parserOptions": { + "project": 'tsconfig.json', + }, + }, + { + "files": ["examples/**/*.ts", "examples/**/*.tsx"], + "parserOptions": { + "project": 'examples/tsconfig.json', + }, + }, + { + "files": ["sandbox/**/*.ts", "sandbox/**/*.tsx"], + "parserOptions": { + "project": 'sandbox/tsconfig.json', + }, + }, + { + "files": ["tests/**/*.ts", "tests/**/*.tsx"], + "parserOptions": { + "project": 'tests/tsconfig.json', + }, + }, + { + "files": ["**/*.ts", "**/*.tsx"], + "extends": [ + "eslint:recommended", + "plugin:import/recommended", + "plugin:import/typescript", + "plugin:react/recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking" + ], + "rules": { + //todo + "@typescript-eslint/no-unused-vars": 0, + "@typescript-eslint/ban-types": 0, + "@typescript-eslint/explicit-module-boundary-types": 0, + "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/no-empty-interface": 0, + "@typescript-eslint/unbound-method": 0, + "@typescript-eslint/prefer-regexp-exec": 0 + } + }, + ], +} diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 98c676ddd..000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "env": { - "browser": true, - "es6": true, - "mocha": true, - "jest": true, - "node": true - }, - "ignorePatterns": [ - "**/node_modules/*", - "bundle.js", - "webpack.config.js" - ], - "extends": [ - "eslint:recommended", - "plugin:react/recommended", - "plugin:@typescript-eslint/eslint-recommended" - ], - "globals": { - "Atomics": "readonly", - "SharedArrayBuffer": "readonly" - }, - "parserOptions": { - "ecmaVersion": 11, - "ecmaFeatures": { - "legacyDecorators": true, - "jsx": true - }, - "sourceType": "module" - }, - "plugins": [ - "react", - "babel", - "@typescript-eslint" - ], - "settings": { - "react": { - "version": "detect" - } - }, - "parser": "@typescript-eslint/parser", - "rules": { - "indent": [ - "error", - 2, - { - } - ], - "linebreak-style": [ - "error", - "unix" - ], - "operator-linebreak": [ - "warn", - "before" - ], - "quotes": [ - "warn", - "double", - { - "avoidEscape": true - } - ], - "semi": [ - "error", - "always" - ], - "no-tabs": [ - "error", - { - "allowIndentationTabs": false - } - ], - "no-unused-vars": [ - "off", - { - "todo": "set to warn", - "args": "all", - "argsIgnorePattern": "^_", - "ignoreRestSiblings": true, - "caughtErrors": "none", - "varsIgnorePattern": "^_" - } - ], - "react/display-name": [ - "off" - ], - "global-require": [ - "off" - ], - "react/prop-types": [ - "off", - { - "todo": "set to warn" - } - ] - } -} diff --git a/.gitignore b/.gitignore index b8ac77315..f25c87338 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ -/examples/bundle.js -/examples/bundle.js.map +/examples/bundle.* /build/ /coverage/ +/sandbox/build/ +/sandbox_simple/build/ +ts_out/ node_modules/ package-lock.json npm-debug.log diff --git a/.npmignore b/.npmignore index 80d23af70..f1a4b393f 100644 --- a/.npmignore +++ b/.npmignore @@ -1,7 +1,9 @@ -/examples/bundle.js -/examples/bundle.js.map +/examples/bundle.* /build/ /coverage/ +/sandbox/build/ +/sandbox_simple/build/ +ts_out/ node_modules/ package-lock.json npm-debug.log diff --git a/.travis.yml b/.travis.yml index c730edc92..516d04080 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - - 10 + - 12 sudo: required dist: trusty before_install: @@ -8,6 +8,7 @@ before_install: # https://stackoverflow.com/questions/22475849/node-js-error-enospc#32600959 - echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p install: - - npm install + - npm run install-all - npm run lint - - npm run build-examples + - npm run build-all + - npm run check-hot diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..3662b3700 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib" +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a5d11f076..2cf09f315 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,15 @@ # Changelog +- 4.1.0 + - Fixed lint errors in code + - Reorganized files in `tests` + - Updated packages + - Now minimum supported NodeJs is 12.13 + - Added TSC linting + - Now ESLint checks types in TS files + - Added new scripts: `install-all`, `clean`, `reinstall`, `build-all`, `check-hot`, `tsc`, `eslint`, `smoke`, `resmoke`. + Renamed `sandbox_ts` to `sandbox-ts`, `sandbox_js` to `sandbox-js`. + - Fixed problems with VSCode's TSLint plugin + - Moved from deprecated `prepublish` to `prepare` in `package.json` - 4.0.4 - Fixed issue #349 with drag-n-drop and office-ui-fabric-react - Fixed issue #413 with func arg with 1 value source which is not value diff --git a/README.md b/README.md index 9c4dc52ee..2ad40ecbc 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,8 @@ See [basic usage](#usage) and [API](#api) below. Demo apps: - [`npm start`](https://github.com/ukrbublik/react-awesome-query-builder/tree/master/examples) - demo app with hot reload of demo code and local library code, uses TS, uses complex config to demonstrate anvanced usage. -- [`npm run sandbox_ts`](https://github.com/ukrbublik/react-awesome-query-builder/tree/master/sandbox) - demo app with hot reload of only demo code (uses latest version of library from npm), uses TS, uses AntDesign widgets. -- [`npm run sandbox_js`](https://github.com/ukrbublik/react-awesome-query-builder/tree/master/sandbox_simple) - demo app with hot reload of only demo code (uses latest version of library from npm), not uses TS, uses vanilla widgets. +- [`npm run sandbox-ts`](https://github.com/ukrbublik/react-awesome-query-builder/tree/master/sandbox) - demo app with hot reload of only demo code (uses latest version of library from npm), uses TS, uses AntDesign widgets. +- [`npm run sandbox-js`](https://github.com/ukrbublik/react-awesome-query-builder/tree/master/sandbox_simple) - demo app with hot reload of only demo code (uses latest version of library from npm), not uses TS, uses vanilla widgets. ## v2 Migration @@ -83,7 +83,7 @@ import {Query, Builder, BasicConfig, Utils as QbUtils} from 'react-awesome-query // For AntDesign widgets only: import AntdConfig from 'react-awesome-query-builder/lib/config/antd'; -import 'react-awesome-query-builder/css/antd.less'; // or import "antd/dist/antd.css"; +import 'antd/dist/antd.css'; // or import "react-awesome-query-builder/css/antd.less"; // For Material-UI widgets only: import MaterialConfig from 'react-awesome-query-builder/lib/config/material'; @@ -408,11 +408,14 @@ To build the component locally, clone this repo then run: Then open localhost:3001 in a browser. Scripts: -- `npm test` - Run tests with Karma and update coverage. Recommended before commits. Requires Node.js v10+ -- `npm run lint` - Run ESLint. Recommended before commits. -- `npm run lint-fix` - Run ESLint with `--fix` option. Recommended before commits. -- `npm run build-examples` - Build examples with webpack. Output path: `examples` -- `npm run build-npm` - Build npm module that can be published. Output path: `lib` +- `npm test` - Run tests with Karma and update coverage. Requires Node.js v10+ +- `npm run lint` - Run ESLint and TSC +- `npm run lint-fix` - Run ESLint with `--fix` option +- `npm run clean` - Clean all data that can be re-generated (like `node_modules`, `build`, `coverage`) +- `npm run install-all` - Install npm packages in root, examples, sandboxes +- `npm run smoke` - Run tests, lint, build lib, build examples, build sandboxes. Recommended before making PR +- `npm run build` - Build npm module to `lib`, build minified production package to `build` +- `npm run build-examples` - Build demo with webpack to `examples`. Then you can open `examples/index.html` Feel free to open PR to add new reusable types/widgets/operators (eg., regex operator for string, IP type & widget). Pull Requests are always welcomed :) diff --git a/examples/demo/config.tsx b/examples/demo/config.tsx index c1edc7279..02bd326b6 100644 --- a/examples/demo/config.tsx +++ b/examples/demo/config.tsx @@ -10,9 +10,7 @@ import moment from "moment"; import ru_RU from "antd/lib/locale-provider/ru_RU"; import { ruRU } from "@material-ui/core/locale"; -// @ts-ignore import AntdConfig from "react-awesome-query-builder/config/antd"; -// @ts-ignore import AntdWidgets from "react-awesome-query-builder/components/widgets/antd"; const { FieldSelect, @@ -20,17 +18,16 @@ const { FieldCascader, FieldTreeSelect, } = AntdWidgets; -// @ts-ignore import MaterialConfig from "react-awesome-query-builder/config/material"; -const skinToConfig = { +const skinToConfig: Record = { vanilla: BasicConfig, antd: AntdConfig, material: MaterialConfig, }; -export default (skin) => { - const InitialConfig = skinToConfig[skin]; +export default (skin: string) => { + const InitialConfig = skinToConfig[skin] as BasicConfig; const conjunctions: Conjunctions = { ...InitialConfig.conjunctions, @@ -227,7 +224,7 @@ export default (skin) => { type: "text", excludeOperators: ["proximity"], fieldSettings: { - validateValue: (val, fieldSettings) => { + validateValue: (val: string, fieldSettings) => { return (val.length < 10); }, }, @@ -241,7 +238,7 @@ export default (skin) => { tableName: "t1", // legacy: PR #18, PR #20 excludeOperators: ["proximity"], fieldSettings: { - validateValue: (val, fieldSettings) => { + validateValue: (val: string, fieldSettings) => { return (val.length < 10 && (val === "" || val.match(/^[A-Za-z0-9_-]+$/) !== null)); }, }, diff --git a/examples/demo/demo.tsx b/examples/demo/demo.tsx index 5695b7c24..193a00f92 100644 --- a/examples/demo/demo.tsx +++ b/examples/demo/demo.tsx @@ -19,17 +19,23 @@ const emptyInitValue: JsonTree = {id: uuid(), type: "group"}; const loadedConfig = loadConfig(initialSkin); let initValue: JsonTree = loadedInitValue && Object.keys(loadedInitValue).length > 0 ? loadedInitValue as JsonTree : emptyInitValue; const initLogic: JsonLogicTree = loadedInitLogic && Object.keys(loadedInitLogic).length > 0 ? loadedInitLogic as JsonLogicTree : undefined; -let initTree; +let initTree: ImmutableTree; //initTree = checkTree(loadTree(initValue), loadedConfig); initTree = checkTree(loadFromJsonLogic(initLogic, loadedConfig), loadedConfig); // <- this will work same -const updateEvent = new CustomEvent("update", { detail: { +// Trick to hot-load new config when you edit `config.tsx` +const updateEvent = new CustomEvent("update", { detail: { config: loadedConfig, _initTree: initTree, _initValue: initValue, } }); window.dispatchEvent(updateEvent); +interface CustomEventDetail { + config: Config; + _initTree: ImmutableTree; + _initValue: JsonTree; +} interface DemoQueryBuilderState { tree: ImmutableTree; @@ -78,7 +84,9 @@ export default class DemoQueryBuilder extends Component<{}, DemoQueryBuilderStat ) - onConfigChanged = ({detail: {config, _initTree, _initValue}}: CustomEvent) => { + onConfigChanged = (e: Event) => { + const {detail: {config, _initTree, _initValue}} = e as CustomEvent; + console.log("Updating config..."); this.setState({ config, }); @@ -92,7 +100,7 @@ export default class DemoQueryBuilder extends Component<{}, DemoQueryBuilderStat }); }; - changeSkin = (e) => { + changeSkin = (e: React.ChangeEvent) => { const skin = e.target.value; const config = loadConfig(e.target.value); this.setState({ diff --git a/examples/index.tsx b/examples/index.tsx index 118ab405e..94b05c1f5 100644 --- a/examples/index.tsx +++ b/examples/index.tsx @@ -4,12 +4,10 @@ import React, {Component} from "react"; import ReactDOM from "react-dom"; import Demo from "./demo/demo"; -import "../css/antd.less"; +import "../css/antd.less"; // or import "antd/dist/antd.css"; import "../css/styles.scss"; //import '../css/compact_styles.scss'; //optional - - const HotDemo = hot(Demo); const rootElement = window.document.getElementById("root"); diff --git a/examples/package.json b/examples/package.json index f1313a5a6..166bfe2c5 100644 --- a/examples/package.json +++ b/examples/package.json @@ -4,23 +4,14 @@ "description": "Local hot-reloadable demo for react-awesome-query-builder", "main": "index.tsx", "scripts": { - "start": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js --hot --color --display-error-details --no-info", - "build": "NODE_ENV=production webpack --config webpack.config.js" + "start": "cross-env NODE_ENV=development webpack serve", + "build": "cross-env NODE_ENV=production CSS=0 webpack", + "analyze": "cross-env NODE_ENV=production ANALYZE=1 webpack" }, "author": "Denis Oblogin (https://github.com/ukrbublik)", "dependencies": { - "@material-ui/core": "^4.11.0", - "@material-ui/icons": "^4.9.1", - "@material-ui/pickers": "^3.2.10", - "antd": ">=4.0.0 <4.5.0", - "material-ui-confirm": "^2.1.1", - "react-awesome-query-builder": "file:..", - "webpack": "^4.44.2", - "webpack-bundle-analyzer": "^3.9.0", - "webpack-cli": "^3.3.10", - "webpack-dev-server": "^3.9.0" + "react-awesome-query-builder": "file:.." }, "devDependencies": { - "cross-env": "^7.0.2" } } diff --git a/examples/tsconfig.json b/examples/tsconfig.json index f69cfa23a..c0efbf734 100644 --- a/examples/tsconfig.json +++ b/examples/tsconfig.json @@ -1,24 +1,32 @@ { "compilerOptions": { - "target": "es5", + "target": "es6", + "module": "esnext", + "jsx": "preserve", "lib": [ "dom", - "dom.iterable", - "es2017" + "dom.iterable" ], - "esModuleInterop": true, - "moduleResolution": "node", - "sourceMap": true, - "outDir": "./ts_out", - "allowJs": true, - "skipLibCheck": true, - "jsx": "react", - "allowSyntheticDefaultImports": true, "experimentalDecorators": true, + "allowJs": true, + "outDir": "ts_out", + "declaration": true, + + "strict": true, + "alwaysStrict": true, "strictNullChecks": false, - "noImplicitAny": false, - "noUnusedLocals": false, - "noUnusedParameters": false + "noImplicitReturns": true, + + "esModuleInterop": true, + "moduleResolution": "node", + "baseUrl": "..", + "paths": { + "react-awesome-query-builder": ["modules"], + "react-awesome-query-builder/*": ["modules/*"], + } }, - "exclude": ["node_modules"] + "include": [ + "demo/**/*", + "index.tsx" + ] } diff --git a/examples/webpack.config.js b/examples/webpack.config.js index b4f6d3d1d..f9dacc665 100644 --- a/examples/webpack.config.js +++ b/examples/webpack.config.js @@ -1,35 +1,94 @@ -var webpack = require('webpack'); -var path = require('path'); +const webpack = require('webpack'); +const path = require('path'); const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; -const isProd = (process.env.NODE_ENV != "development"); +const MomentLocalesPlugin = require('moment-locales-webpack-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); + +const MODE = process.env.NODE_ENV || "development"; +const PORT = 3001; +const lib_name = 'react-awesome-query-builder'; +const isProd = (MODE != "development"); +const isDev = (MODE == "development"); +const isAnalyze = process.env.ANALYZE == "1"; +const isSeparateCss = process.env.CSS == "1"; +const EXAMPLES = __dirname; +const RAQB_NODE_MODULES = path.resolve(EXAMPLES, '../node_modules/'); +const MODULES = path.resolve(EXAMPLES, '../modules/'); +const DIST = path.resolve(EXAMPLES, '.'); + +let plugins = [ + new webpack.DefinePlugin({ + 'process.env': { + NODE_ENV: JSON.stringify(MODE), + } + }), +]; +let aliases = { + [lib_name]: MODULES +}; +let style_loaders = [{ + loader: "style-loader" +}]; -var plugins = []; if (isProd) { plugins = [ + ...plugins, new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /en|ru|es-us/), - //new BundleAnalyzerPlugin(), - new webpack.DefinePlugin({ - 'process.env': { - NODE_ENV: JSON.stringify(process.env.NODE_ENV || "production"), - } + new MomentLocalesPlugin({ + localesToKeep: ['es-us', 'ru'], }), ]; -} else { +} +if (isSeparateCss) { plugins = [ - new webpack.DefinePlugin({ - 'process.env': { - NODE_ENV: JSON.stringify(process.env.NODE_ENV || "development"), - } + ...plugins, + new MiniCssExtractPlugin({ + filename: path.resolve(DIST, 'bundle.css') }), ]; + style_loaders = [ + MiniCssExtractPlugin.loader + ]; +} +if (isAnalyze) { + plugins = [ + ...plugins, + new BundleAnalyzerPlugin() + ]; +} +if (isDev) { + aliases = { + ...aliases, + 'react-dom': '@hot-loader/react-dom', + }; } +const babel_options = { + presets: [ + '@babel/preset-env', + '@babel/preset-react', + '@babel/preset-typescript', // or can use 'ts-loader' instead + ], + plugins: [ + ["@babel/plugin-proposal-decorators", { "legacy": true }], + ["@babel/plugin-proposal-class-properties", { "loose": true }], + ["@babel/plugin-proposal-private-methods", { "loose": true }], + "@babel/plugin-transform-runtime", // or can use 'react-hot-loader/webpack' instead + "react-hot-loader/babel", + ["import", { + "libraryName": "antd", + "style": false, + "libraryDirectory": "es" + }], + ] +}; + module.exports = { plugins, - mode: process.env.NODE_ENV || "development", + mode: MODE, devtool: isProd ? 'source-map' : 'source-map', devServer: { - port: 3001, + port: PORT, inline: true, historyApiFallback: true, hot: true, @@ -39,20 +98,16 @@ module.exports = { './index', ], output: { - path: __dirname, + path: DIST, filename: 'bundle.js' }, resolve: { modules: [ + // combine with parent node_modules 'node_modules', - path.resolve(__dirname, '../node_modules'), + RAQB_NODE_MODULES, ], - alias: { - 'react-awesome-query-builder': path.resolve(__dirname, '../modules'), - 'react-dom': '@hot-loader/react-dom', - 'antd': path.resolve(__dirname, 'node_modules/antd'), - '@ant-design': path.resolve(__dirname, 'node_modules/@ant-design'), - }, + alias: aliases, extensions: ['.tsx', '.ts', '.js', '.jsx'] }, module: { @@ -69,36 +124,22 @@ module.exports = { // }, { test: /\.[jt]sx?$/, - loaders: 'babel-loader', - options: { - presets: [ - '@babel/preset-env', - '@babel/preset-react', - '@babel/preset-typescript', // or can use 'ts-loader' instead - ], - plugins: [ - ["@babel/plugin-proposal-decorators", { "legacy": true }], - ["@babel/plugin-proposal-class-properties", { "loose": true }], - "@babel/plugin-transform-runtime", // or can use 'react-hot-loader/webpack' instead - "react-hot-loader/babel", - ["import", { - "libraryName": "antd", - "style": false, - "libraryDirectory": "es" - }], - ] - }, - exclude: /node_modules/ + exclude: /node_modules/, + use: [{ + loader: 'babel-loader', + options: { + ...babel_options, + cacheDirectory: true + } + }] }, { test: /\.css$/, - use: ["style-loader", "css-loader"] + use: [...style_loaders, "css-loader"] }, { test: /\.scss$/, - use: [{ - loader: "style-loader" - }, { + use: [...style_loaders, { loader: "css-loader" }, { loader: "sass-loader" @@ -106,20 +147,24 @@ module.exports = { }, { test: /\.less$/, - use: [{ - loader: "style-loader" - }, { + use: [...style_loaders, { loader: "css-loader" }, { loader: "less-loader", options: { - javascriptEnabled: true + lessOptions: { + javascriptEnabled: true + } } }] }, { test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, - loader: "url-loader?limit=10000&minetype=application/font-woff" + loader: "url-loader", + options: { + limit: 10000, + minetype: 'application/font-woff' + } }, { test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, diff --git a/karma.conf.js b/karma.conf.js deleted file mode 100644 index a1fcbf72e..000000000 --- a/karma.conf.js +++ /dev/null @@ -1,72 +0,0 @@ -const puppeteer = require('puppeteer'); -if (puppeteer.executablePath().indexOf('/home/ukrbublik/') == 0) { - // ignore for my local dev -} else { - process.env.CHROME_BIN = puppeteer.executablePath(); -} -process.env.TZ = 'Etc/UTC'; -process.env.BABEL_ENV = 'test'; // Set the proper environment for babel - -module.exports = function(config) { - config.set({ - basePath: '', - frameworks: ['mocha', 'chai', 'es6-shim'], - plugins: [ - 'karma-mocha', - 'karma-chai', - 'karma-es6-shim', - 'karma-chrome-launcher', - 'karma-sourcemap-loader', - 'karma-webpack', - 'karma-mocha-reporter', - 'karma-coverage', - ], - - files: [ - { - pattern: 'karma.tests.js', - watched: true, - served: true, - included: true, - }, - ], - exclude: [], - preprocessors: { - 'karma.tests.js': ['webpack', 'sourcemap'], - 'modules/**/*': ['coverage'] - }, - webpack: require('./webpack-test.config'), - webpackMiddleware: { - stats: 'errors-only' - }, - - reporters: ['progress', 'coverage'], - - coverageReporter: { - dir: 'coverage', - reporters: [ - { type: 'html', subdir: 'html' }, - { type: 'text-summary' }, - { type: 'lcov' } - ], - includeAllSources: true, - instrumenterOptions: { - istanbul: { noCompact: true } - } - }, - - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: false, - browsers: ['ChromeHeadlessNoSandbox'], - customLaunchers: { - ChromeHeadlessNoSandbox: { - base: 'ChromeHeadless', - flags: ['--no-sandbox'] - } - }, - singleRun: true, - concurrency: 1 - }) -} diff --git a/karma.tests.js b/karma.tests.js deleted file mode 100644 index a9b3943d6..000000000 --- a/karma.tests.js +++ /dev/null @@ -1,7 +0,0 @@ -import Enzyme from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; - -Enzyme.configure({adapter: new Adapter()}); - -const context = require.context('./tests', true, /\.test\.js$/); -context.keys().forEach(context); diff --git a/modules/components/containers/Draggable.jsx b/modules/components/containers/Draggable.jsx index d33da8502..66ab91593 100644 --- a/modules/components/containers/Draggable.jsx +++ b/modules/components/containers/Draggable.jsx @@ -3,8 +3,8 @@ import PropTypes from "prop-types"; const classNames = require("classnames"); -export default (className) => (GroupOrRule) => { - return class Draggable extends PureComponent { +export default (className) => (GroupOrRule) => + class Draggable extends PureComponent { static propTypes = { isDraggingTempo: PropTypes.bool, isDraggingMe: PropTypes.bool, @@ -66,4 +66,3 @@ export default (className) => (GroupOrRule) => { } }; -}; diff --git a/modules/components/containers/GroupContainer.jsx b/modules/components/containers/GroupContainer.jsx index 509979a88..b96f3e8e7 100644 --- a/modules/components/containers/GroupContainer.jsx +++ b/modules/components/containers/GroupContainer.jsx @@ -6,7 +6,7 @@ import {pureShouldComponentUpdate, useOnPropsChanged} from "../../utils/reactUti import {connect} from "react-redux"; -export default (Group) => { +const createGroupContainer = (Group) => class GroupContainer extends Component { static propTypes = { //tree: PropTypes.instanceOf(Immutable.Map).isRequired, @@ -198,8 +198,10 @@ export default (Group) => { ); } - } + }; + +export default (Group) => { const ConnectedGroupContainer = connect( (state) => { return { @@ -211,7 +213,7 @@ export default (Group) => { { context } - )(GroupContainer); + )(createGroupContainer(Group)); ConnectedGroupContainer.displayName = "ConnectedGroupContainer"; return ConnectedGroupContainer; diff --git a/modules/components/containers/RuleContainer.jsx b/modules/components/containers/RuleContainer.jsx index 1df0fc2b1..02333e90a 100644 --- a/modules/components/containers/RuleContainer.jsx +++ b/modules/components/containers/RuleContainer.jsx @@ -7,7 +7,7 @@ import {connect} from "react-redux"; const classNames = require("classnames"); -export default (Rule) => { +const createRuleContainer = (Rule) => class RuleContainer extends Component { static propTypes = { id: PropTypes.string.isRequired, @@ -155,9 +155,10 @@ export default (Rule) => { ); } - } + }; +export default (Rule) => { const ConnectedRuleContainer = connect( (state) => { return { @@ -169,7 +170,7 @@ export default (Rule) => { { context } - )(RuleContainer); + )(createRuleContainer(Rule)); ConnectedRuleContainer.displayName = "ConnectedRuleContainer"; return ConnectedRuleContainer; diff --git a/modules/components/containers/SortableContainer.jsx b/modules/components/containers/SortableContainer.jsx index bff9223d6..59c929f38 100644 --- a/modules/components/containers/SortableContainer.jsx +++ b/modules/components/containers/SortableContainer.jsx @@ -10,9 +10,8 @@ import {pureShouldComponentUpdate, useOnPropsChanged} from "../../utils/reactUti const isDev = () => (process && process.env && process.env.NODE_ENV == "development"); -export default (Builder, CanMoveFn = null) => { +const createSortableContainer = (Builder, CanMoveFn = null) => class SortableContainer extends Component { - static propTypes = { tree: PropTypes.any.isRequired, //instanceOf(Immutable.Map) actions: PropTypes.object.isRequired, // {moveItem: Function, ..} @@ -33,7 +32,7 @@ export default (Builder, CanMoveFn = null) => { shouldComponentUpdate(nextProps, nextState) { let prevProps = this.props; let prevState = this.state; - + let should = pureShouldComponentUpdate(this)(nextProps, nextState); if (should) { if (prevState == nextState && prevProps != nextProps) { @@ -545,9 +544,10 @@ export default (Builder, CanMoveFn = null) => { onDragStart={this.onDragStart} />; } + }; - } +export default (Builder, CanMoveFn = null) => { const ConnectedSortableContainer = connect( (state) => { return { @@ -564,10 +564,9 @@ export default (Builder, CanMoveFn = null) => { { context } - )(SortableContainer); + )(createSortableContainer(Builder, CanMoveFn)); ConnectedSortableContainer.displayName = "ConnectedSortableContainer"; return ConnectedSortableContainer; - }; diff --git a/modules/components/widgets/antd/index.d.ts b/modules/components/widgets/antd/index.d.ts index 762b7e3c2..e79550096 100644 --- a/modules/components/widgets/antd/index.d.ts +++ b/modules/components/widgets/antd/index.d.ts @@ -1,3 +1,3 @@ import {AntdWidgets} from "../../.."; -const AntdWidgets: AntdWidgets; +declare const AntdWidgets: AntdWidgets; export default AntdWidgets; diff --git a/modules/components/widgets/material/index.d.ts b/modules/components/widgets/material/index.d.ts index 8d5b09781..17ad4de6a 100644 --- a/modules/components/widgets/material/index.d.ts +++ b/modules/components/widgets/material/index.d.ts @@ -1,3 +1,3 @@ import {MaterialWidgets} from "../../.."; -const MaterialWidgets: MaterialWidgets; +declare const MaterialWidgets: MaterialWidgets; export default MaterialWidgets; diff --git a/modules/config/antd/index.d.ts b/modules/config/antd/index.d.ts index 42d5a20c5..2307f8e21 100644 --- a/modules/config/antd/index.d.ts +++ b/modules/config/antd/index.d.ts @@ -1,3 +1,3 @@ -import {BasicConfig} from '../..'; -const AntdConfig: BasicConfig; +import {BasicConfig} from "../.."; +declare const AntdConfig: BasicConfig; export default AntdConfig; diff --git a/modules/config/material/index.d.ts b/modules/config/material/index.d.ts index 2352e8215..5b51f8e57 100644 --- a/modules/config/material/index.d.ts +++ b/modules/config/material/index.d.ts @@ -1,3 +1,3 @@ import {BasicConfig} from "../.."; -const MaterialConfig: BasicConfig; +declare const MaterialConfig: BasicConfig; export default MaterialConfig; diff --git a/modules/import/jsonLogic.js b/modules/import/jsonLogic.js index 4876ee74a..d8b9e9222 100644 --- a/modules/import/jsonLogic.js +++ b/modules/import/jsonLogic.js @@ -1,11 +1,10 @@ import uuid from "../utils/uuid"; -import {defaultValue} from "../utils/stuff"; +import {defaultValue, isJsonLogic} from "../utils/stuff"; import {getFieldConfig, extendConfig, normalizeField} from "../utils/configUtils"; import {getWidgetForFieldOp} from "../utils/ruleUtils"; import {loadTree} from "./tree"; import {defaultConjunction, defaultGroupConjunction} from "../utils/defaultUtils"; import moment from "moment"; -import {isJsonLogic} from "../utils/stuff"; // http://jsonlogic.com/ diff --git a/modules/stores/tree.js b/modules/stores/tree.js index d486fd95c..035af6192 100644 --- a/modules/stores/tree.js +++ b/modules/stores/tree.js @@ -14,11 +14,11 @@ import { getFuncConfig, getFieldConfig, getFieldWidgetConfig, getOperatorConfig } from "../utils/configUtils"; import { - getOperatorsForField, getFirstOperator, getWidgetForFieldOp + getOperatorsForField, getFirstOperator, getWidgetForFieldOp, + getNewValueForFieldOp } from "../utils/ruleUtils"; import {deepEqual, defaultValue} from "../utils/stuff"; import {validateValue} from "../utils/validation"; -import {getNewValueForFieldOp} from "../utils/ruleUtils"; const hasChildren = (tree, path) => tree.getIn(expandTreePath(path, "children1")).size > 0; diff --git a/package.json b/package.json index 5c246d4f6..5b3014baa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-awesome-query-builder", - "version": "4.0.4", + "version": "4.1.0", "description": "User-friendly query builder for React. Demo: https://ukrbublik.github.io/react-awesome-query-builder", "keywords": [ "query-builder", @@ -28,19 +28,37 @@ "main": "lib", "types": "modules/index.d.ts", "scripts": { - "prepublish": "npm run build-npm", + "prepare": "npm run build-npm", "for-npm": "./scripts/for-npm.sh", "for-gpr": "./scripts/for-gpr.sh", "build-npm": "./scripts/build-npm.sh", - "build-global": "NODE_ENV=production COMPRESS=1 ANALYZE=0 webpack modules/index.js", - "build-examples": "./scripts/build-examples.sh", + "check-hot": "node ./scripts/check-hot.js", + "build-global": "NODE_ENV=production COMPRESS=1 webpack", + "build": "npm run build-npm && npm run build-global", + "build-examples": "cd examples && npm run build", + "build-sandbox-ts": "cd sandbox && npm run build", + "build-sandbox-js": "cd sandbox_simple && npm run build", + "build-all": "npm run build-npm && npm run build-global && npm run build-examples && npm run build-sandbox-ts && npm run build-sandbox-js", "examples": "cd examples && npm i && npm start", - "sandbox_ts": "cd sandbox && npm i && npm start", - "sandbox_js": "cd sandbox_simple && npm i && npm start", + "sandbox-ts": "cd sandbox && npm i && npm start", + "sandbox-js": "cd sandbox_simple && npm i && npm start", + "sandbox": "npm run sandbox-ts", "start": "npm i && npm run examples", - "test": "karma start karma.conf.js", - "lint-fix": "./node_modules/.bin/eslint --ext .jsx --ext .js --ext .tsx --fix ./modules/ ./sandbox/ ./sandbox_simple/ ./examples/ ./tests/", - "lint": "./node_modules/.bin/eslint --ext .jsx --ext .js --ext .tsx ./modules/ ./sandbox/ ./sandbox_simple/ ./examples/ ./tests/" + "test": "karma start ./tests/karma.conf.js", + "tsc-lib": "tsc -p . --noEmit", + "tsc-examples": "tsc -p ./examples --noEmit", + "tsc-sandbox": "tsc -p ./sandbox --noEmit", + "tsc-tests": "tsc -p ./tests --noEmit", + "tsc": "npm run tsc-lib && npm run tsc-examples && npm run tsc-sandbox && npm run tsc-tests", + "eslint-fix": "./node_modules/.bin/eslint --ext .jsx --ext .js --ext .tsx --ext .ts --fix ./modules/ ./sandbox/ ./sandbox_simple/ ./examples/ ./tests/", + "eslint": " ./node_modules/.bin/eslint --ext .jsx --ext .js --ext .tsx --ext .ts ./modules/ ./sandbox/ ./sandbox_simple/ ./examples/ ./tests/", + "lint": "npm run eslint && npm run tsc", + "lint-fix": "npm run eslint-fix", + "clean": "./scripts/clean.sh", + "install-all": "npm i && npm i -C examples && npm i -C sandbox && npm i -C sandbox_simple", + "reinstall": "npm run clean && npm run install-all", + "smoke": "npm run lint && npm run test && npm run build-all && npm run check-hot", + "resmoke": "npm run reinstall && npm run smoke" }, "repository": { "type": "git", @@ -54,99 +72,104 @@ "homepage": "https://github.com/ukrbublik/react-awesome-query-builder", "funding": "https://opencollective.com/react-awesome-query-builder", "engines": { - "node": ">=10.14", + "node": ">=12.13", "npm": ">=6" }, "dependencies": { "@date-io/moment": "^1.3.13", - "classnames": "^2.2.5", - "clone": "^2.1.1", - "immutable": "^3.7.6", - "lodash": "^4.17.20", - "moment": "^2.28.0", - "prop-types": "^15.6.0", - "react-redux": "^7.2.1", - "redux": "^4.0.5", - "sqlstring": "^2.3.1" + "classnames": "^2.3.1", + "clone": "^2.1.2", + "immutable": "^3.8.2", + "lodash": "^4.17.21", + "moment": "^2.29.1", + "prop-types": "^15.7.2", + "react-redux": "~7.1.3", + "redux": "^4.1.0", + "sqlstring": "^2.3.2" }, "peerDependencies": { - "@material-ui/core": "^4.11.0", - "@material-ui/icons": "^4.9.1", + "@material-ui/core": "^4.9.0", + "@material-ui/icons": "^4.0.0", "@material-ui/pickers": "^3.2.10", - "antd": ">=4.0.0 <4.5.0", - "material-ui-confirm": "^2.1.1", - "react": "^0.14.6 || ^15.0.0 || ^16.4.1 || ^17.0.1", - "react-dom": "^0.14.6 || ^15.0.0 || ^16.4.1 || ^17.0.1", - "react-redux": "^4.0.6 || ^5.0.0 || ^6.0.0 || ^7.2.1", - "redux": "^3.5.0 || ^4.0.5" + "material-ui-confirm": "^2.0.1", + "antd": "^4.0.0", + "react": "^16.8.4 || ^17.0.1", + "react-dom": "^16.8.4 || ^17.0.1" }, "devDependencies": { - "@babel/cli": "^7.7.4", - "@babel/core": "^7.7.4", - "@babel/plugin-proposal-class-properties": "^7.7.4", - "@babel/plugin-proposal-decorators": "^7.7.4", - "@babel/plugin-transform-modules-commonjs": "^7.7.4", - "@babel/plugin-transform-runtime": "^7.7.4", - "@babel/preset-env": "^7.7.4", - "@babel/preset-react": "^7.7.4", - "@babel/preset-typescript": "^7.7.4", - "@hot-loader/react-dom": "^16.4.1", - "@material-ui/core": "^4.11.0", - "@material-ui/icons": "^4.9.1", - "@material-ui/pickers": "^3.2.10", - "@types/classnames": "^2.2.5", - "@types/lodash": "^4.6", - "@types/node": "12.12.14", - "@types/prop-types": "^15.6.0", - "@types/react": "^16.4.1", - "@types/react-dom": "^16.4.1", - "@typescript-eslint/eslint-plugin": "^3.2.0", - "@typescript-eslint/parser": "^3.2.0", - "antd": ">=4.0.0 <4.5.0", - "babel-eslint": "^10.1.0", - "babel-loader": "^8.0.6", - "babel-plugin-import": "^1.13.0", + "@babel/cli": "^7.14.5", + "@babel/core": "^7.14.5", + "@babel/plugin-proposal-class-properties": "^7.14.5", + "@babel/plugin-proposal-decorators": "^7.14.5", + "@babel/plugin-proposal-private-methods": "^7.14.5", + "@babel/plugin-transform-modules-commonjs": "^7.14.5", + "@babel/plugin-transform-runtime": "^7.14.5", + "@babel/preset-env": "^7.14.5", + "@babel/preset-react": "^7.14.5", + "@babel/preset-typescript": "^7.14.5", + "@date-io/dayjs": "^1.3.13", + "dayjs": "^1.10.5", + "@hot-loader/react-dom": "^16.14.0", + "@material-ui/core": "^4.11.4", + "@material-ui/icons": "^4.11.2", + "@material-ui/pickers": "^3.3.10", + "@types/chai": "^4.2.18", + "@types/enzyme": "^3.10.8", + "@types/lodash": "^4.14.170", + "@types/mocha": "^8.2.2", + "@types/node": "^15.12.2", + "@types/prop-types": "^15.7.3", + "@types/react": "^16.14.0", + "@types/react-dom": "^17.0.8", + "@typescript-eslint/eslint-plugin": "^4.27.0", + "@typescript-eslint/parser": "^4.27.0", + "antd": "^4.16.3", + "babel-loader": "^8.2.2", + "babel-plugin-import": "^1.13.3", "babel-plugin-istanbul": "^6.0.0", - "chai": "^4.2.0", - "codecov": "^3.7.0", - "compression-webpack-plugin": "^5.0.2", - "css-loader": "^3.2.0", + "chai": "^4.3.2", + "codecov": "^3.8.2", + "compression-webpack-plugin": "^8.0.0", + "cross-env": "^7.0.3", + "css-loader": "^5.2.6", "enzyme": "^3.11.0", - "enzyme-adapter-react-16": "^1.15.2", - "eslint": "^7.9.0", - "eslint-plugin-babel": "^5.3.0", - "eslint-plugin-react": "^7.20.0", - "fibers": "^4.0.2", - "file-loader": "^5.0.2", - "karma": "^5.2.2", + "enzyme-adapter-react-16": "^1.15.6", + "eslint": "^7.28.0", + "eslint-import-resolver-webpack": "^0.13.1", + "eslint-plugin-babel": "^5.3.1", + "eslint-plugin-import": "^2.23.4", + "eslint-plugin-react": "^7.24.0", + "fibers": "^5.0.0", + "file-loader": "^6.2.0", + "karma": "^6.3.4", "karma-chai": "^0.1.0", "karma-chrome-launcher": "^3.1.0", - "karma-coverage": "^2.0.2", + "karma-coverage": "^2.0.3", "karma-es6-shim": "^1.0.0", "karma-mocha": "^2.0.1", "karma-mocha-reporter": "^2.2.5", - "karma-sourcemap-loader": "^0.3.7", - "karma-webpack": "^4.0.2", - "less": "^3.10.3", - "less-loader": "^5.0.0", - "material-ui-confirm": "^2.1.1", - "mocha": "^7.2.0", - "node-sass": "^4.14.1", - "puppeteer": "^3.0.2", - "react": "^16.4.1", - "react-dom": "^16.4.1", - "react-hot-loader": "^4.8.8", - "sass": "^1.26.11", - "sass-loader": "^8.0.0", - "sinon": "^9.0.2", - "sourcemap": "^0.1.0", - "style-loader": "^1.0.1", - "ts-loader": "^6.2.1", - "typescript": "^3.7.2", - "url-loader": "^3.0.0", - "webpack": "^4.44.2", - "webpack-bundle-analyzer": "^3.9.0", - "webpack-cli": "^3.3.10", - "webpack-dev-server": "^3.11.0" + "karma-sourcemap-loader": "^0.3.8", + "karma-webpack": "^5.0.0", + "less": "^4.1.1", + "less-loader": "^9.1.0", + "material-ui-confirm": "^2.1.2", + "mini-css-extract-plugin": "^1.6.0", + "mocha": "^9.0.0", + "moment-locales-webpack-plugin": "^1.2.0", + "puppeteer": "^10.0.0", + "react": "^16.14.0", + "react-dom": "^16.14.0", + "react-hot-loader": "^4.13.0", + "sass": "^1.35.0", + "sass-loader": "^12.1.0", + "sinon": "^11.1.1", + "style-loader": "^2.0.0", + "ts-loader": "^9.2.3", + "typescript": "^4.3.2", + "url-loader": "^4.1.1", + "webpack": "^5.39.0", + "webpack-cli": "^4.7.2", + "webpack-bundle-analyzer": "^4.4.2", + "webpack-dev-server": "^3.11.2" } } diff --git a/sandbox/package.json b/sandbox/package.json index 1a5cc326b..aa0882467 100644 --- a/sandbox/package.json +++ b/sandbox/package.json @@ -15,23 +15,19 @@ "eject": "SKIP_PREFLIGHT_CHECK=true react-scripts eject" }, "author": "Denis Oblogin (https://github.com/ukrbublik)", - "homepage": "https://ukrbublik.github.io/react-awesome-query-builder/", "dependencies": { - "@types/lodash": "^4.14.161", - "@types/node": "^13.13.21", - "@types/react": "^16.9.49", - "@types/react-dom": "^16.9.7", - "antd": ">=4.0.0 <4.5.0", - "@material-ui/core": "^4.11.0", - "@material-ui/icons": "^4.9.1", - "@material-ui/pickers": "^3.2.10", - "material-ui-confirm": "^2.1.1", - "lodash": "^4.6", - "react": "^16.4.1", - "react-awesome-query-builder": "^4.0.3", - "react-dom": "^16.4.1", "react-scripts": "^3.4.3", - "typescript": "3.4.5" + "react-awesome-query-builder": "^4.0.3", + "react": "^16.14.0", + "react-dom": "^16.14.0", + "antd": ">=4.0.0 <4.5.0", + "@material-ui/core": "^4.11.4", + "@material-ui/icons": "^4.11.2", + "@material-ui/pickers": "^3.3.10", + "material-ui-confirm": "^2.1.2", + "@types/lodash": "^4.14.170", + "@types/react": "^16.14.0", + "@types/react-dom": "^17.0.8" }, "browserslist": { "production": [ diff --git a/sandbox/src/demo/config.tsx b/sandbox/src/demo/config.tsx index 01dcbbd55..9e5002725 100644 --- a/sandbox/src/demo/config.tsx +++ b/sandbox/src/demo/config.tsx @@ -10,17 +10,16 @@ import ru_RU from "antd/lib/locale-provider/ru_RU"; import { ruRU } from "@material-ui/core/locale"; import AntdConfig from "react-awesome-query-builder/lib/config/antd"; import AntdWidgets from "react-awesome-query-builder/lib/components/widgets/antd"; +import MaterialConfig from "react-awesome-query-builder/lib/config/material"; const { FieldSelect, FieldDropdown, FieldCascader, FieldTreeSelect, } = AntdWidgets; -import MaterialConfig from "react-awesome-query-builder/lib/config/material"; const InitialConfig = AntdConfig; // or BasicConfig or MaterialConfig - ////////////////////////////////////////////////////////////////////// const fields: Fields = { @@ -34,7 +33,7 @@ const fields: Fields = { type: "text", excludeOperators: ["proximity"], fieldSettings: { - validateValue: (val, fieldSettings) => { + validateValue: (val: string, fieldSettings) => { return (val.length < 10); }, }, @@ -48,7 +47,7 @@ const fields: Fields = { tableName: "t1", // legacy: PR #18, PR #20 excludeOperators: ["proximity"], fieldSettings: { - validateValue: (val, fieldSettings) => { + validateValue: (val: string, fieldSettings) => { return (val.length < 10 && (val === "" || val.match(/^[A-Za-z0-9_-]+$/) !== null)); }, }, diff --git a/sandbox/src/demo/config_simple.tsx b/sandbox/src/demo/config_simple.tsx index 12864b9be..73c8722fb 100644 --- a/sandbox/src/demo/config_simple.tsx +++ b/sandbox/src/demo/config_simple.tsx @@ -10,13 +10,13 @@ import ru_RU from "antd/lib/locale-provider/ru_RU"; import { ruRU } from "@material-ui/core/locale"; import AntdConfig from "react-awesome-query-builder/lib/config/antd"; import AntdWidgets from "react-awesome-query-builder/lib/components/widgets/antd"; +import MaterialConfig from "react-awesome-query-builder/lib/config/material"; const { FieldSelect, FieldDropdown, FieldCascader, FieldTreeSelect, } = AntdWidgets; -import MaterialConfig from "react-awesome-query-builder/lib/config/material"; const InitialConfig = AntdConfig; // or BasicConfig or MaterialConfig @@ -37,7 +37,7 @@ const fields: Fields = { valuePlaceholder: "Enter name", }, fieldSettings: { - validateValue: (val, fieldSettings) => { + validateValue: (val: string, fieldSettings) => { return (val.length < 10); }, }, @@ -46,7 +46,7 @@ const fields: Fields = { type: "text", excludeOperators: ["proximity"], fieldSettings: { - validateValue: (val, fieldSettings) => { + validateValue: (val: string, fieldSettings) => { return (val.length < 10 && (val === "" || val.match(/^[A-Za-z0-9_-]+$/) !== null)); }, }, diff --git a/sandbox/tsconfig.json b/sandbox/tsconfig.json index e53feff20..c67ebe4b0 100644 --- a/sandbox/tsconfig.json +++ b/sandbox/tsconfig.json @@ -1,26 +1,33 @@ { "compilerOptions": { - "target": "es5", + "target": "es6", + "module": "esnext", + "jsx": "preserve", "lib": [ "dom", - "dom.iterable", - "esnext" + "dom.iterable" ], + "experimentalDecorators": true, "allowJs": true, - "skipLibCheck": true, + "outDir": "ts_out", + "declaration": true, + + "strict": true, + "alwaysStrict": true, + "strictNullChecks": false, + "noImplicitReturns": true, + "esModuleInterop": true, + "moduleResolution": "node", + "skipLibCheck": true, + "allowSyntheticDefaultImports": true, - "strict": true, "forceConsistentCasingInFileNames": true, - "module": "esnext", - "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, - "strictNullChecks": false, - "noEmit": true, - "jsx": "preserve" + "noEmit": true }, "include": [ - "src" + "src/**/*" ] } diff --git a/sandbox_simple/package.json b/sandbox_simple/package.json index 480e32187..529be0187 100644 --- a/sandbox_simple/package.json +++ b/sandbox_simple/package.json @@ -15,13 +15,11 @@ "eject": "SKIP_PREFLIGHT_CHECK=true react-scripts eject" }, "author": "Denis Oblogin (https://github.com/ukrbublik)", - "homepage": "https://ukrbublik.github.io/react-awesome-query-builder/", "dependencies": { - "lodash": "^4.6", - "react": "^16.4.1", + "react-scripts": "^3.4.3", "react-awesome-query-builder": "^4.0.3", - "react-dom": "^16.4.1", - "react-scripts": "^3.4.3" + "react": "^16.14.0", + "react-dom": "^16.14.0" }, "browserslist": { "production": [ diff --git a/scripts/build-examples.sh b/scripts/build-examples.sh deleted file mode 100755 index c53ebf33c..000000000 --- a/scripts/build-examples.sh +++ /dev/null @@ -1,4 +0,0 @@ -cd examples -npm i -npm run build -cd .. diff --git a/scripts/build-npm.sh b/scripts/build-npm.sh index ce5ade7c1..e3559ec23 100755 --- a/scripts/build-npm.sh +++ b/scripts/build-npm.sh @@ -1,6 +1,7 @@ rm -rf lib babel -d lib ./modules -node-sass css/ -o lib/css/ --output-style compressed +sass css/:lib/css/ --no-source-map --style=expanded +cp css/antd.less lib/css/antd.less cp modules/index.d.ts lib/index.d.ts cp modules/config/antd/index.d.ts lib/config/antd/index.d.ts cp modules/config/material/index.d.ts lib/config/material/index.d.ts diff --git a/scripts/check-hot.js b/scripts/check-hot.js new file mode 100755 index 000000000..716d1dfef --- /dev/null +++ b/scripts/check-hot.js @@ -0,0 +1,106 @@ +const { spawn, execSync } = require('child_process'); +const COMPILE_TIMEOUT = 30*1000; // 30 s +const EXIT_TIMEOUT = 1*1000; // 1 s +const WEBPACK_PORT = 3001; + +let prcOutBuf = Buffer.alloc(0); +let prcErrBuf = Buffer.alloc(0); +let isCompiled; +let timerCompile; + +const prc = spawn('npm', ['run', 'examples']); + +prc.stdout.on('data', (data) => { + prcOutBuf = Buffer.concat([prcOutBuf, data]); + check(); +}); + +prc.stderr.on('data', (data) => { + prcErrBuf = Buffer.concat([prcErrBuf, data]); + check(); +}); + +prc.on('exit', (code) => { + end(`webpack exited with code ${code}`); +}); + +// Remove ANSI color from webpack output +const cleanStr = (str) => { + //https://github.com/chalk/ansi-regex/blob/main/index.js + const pattern = [ + '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)', + '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))' + ].join('|'); + const regex = new RegExp(pattern, 'g'); + + return str.replace(regex, ''); +}; + +const startTimerCompile = () => { + timerCompile = setTimeout(() => { + end(`webpack compile timeout exceeded (${COMPILE_TIMEOUT/1000} s)`); + }, COMPILE_TIMEOUT); +}; + +const stopTimerCompile = () => { + if (timerCompile) + clearTimeout(timerCompile); + timerCompile = null; +}; + +const end = (err) => { + stopTimerCompile(); + + // Kill `npm run examples` + prc.kill(); + + // Kill webpack + try { + const webpack_pid = parseInt(execSync(`lsof -t -i tcp:${WEBPACK_PORT}`, { + encoding: 'utf8' + })); + process.kill(webpack_pid); + } catch(e) { + console.error('Failed to kill webpack!', e); + } + + // Print webpack out + const prcOut = cleanStr(prcOutBuf.toString()); + const prcErr = cleanStr(prcErrBuf.toString()); + console.log('------------------ [ webpack out ]'); + console.log(prcOut); + console.log('------------------ [ webpack err ]'); + console.log(prcErr); + console.log('------------------'); + + // Return 0 or 1 + if (err) { + console.log(err); + process.exit(1); + } else { + console.log("Seems like all right with webpack"); + process.exit(0); + } +}; + +const check = () => { + const prcOutClean = cleanStr(prcOutBuf.toString()); + + if (prcOutClean.indexOf('「wdm」: Failed to compile.') != -1) { + isCompiled = false; + stopTimerCompile(); + setTimeout(() => { + end(`webpack failed to compile`); + }, EXIT_TIMEOUT); + } + + if (prcOutClean.indexOf('「wdm」: Compiled successfully.') != -1) { + isCompiled = true; + stopTimerCompile(); + setTimeout(() => { + end(); + }, EXIT_TIMEOUT); + } +}; + +startTimerCompile(); diff --git a/scripts/clean.sh b/scripts/clean.sh new file mode 100755 index 000000000..9c9c69330 --- /dev/null +++ b/scripts/clean.sh @@ -0,0 +1,21 @@ +rm -f ./package-lock.json +rm -rf ./node_modules +rm -rf ./build +rm -rf ./lib +rm -rf ./coverage +rm -rf ./ts_out +rm -rf ./tests/ts_out + +rm -rf ./examples/package-lock.json +rm -rf ./examples/node_modules +rm -f ./examples/bundle.* +rm -rf ./examples/ts_out + +rm -rf ./sandbox/package-lock.json +rm -rf ./sandbox/node_modules +rm -rf ./sandbox/ts_out +rm -rf ./sandbox/build + +rm -rf ./sandbox_simple/package-lock.json +rm -rf ./sandbox_simple/node_modules +rm -rf ./sandbox_simple/build diff --git a/tests/karma.conf.js b/tests/karma.conf.js new file mode 100644 index 000000000..80f2df5ea --- /dev/null +++ b/tests/karma.conf.js @@ -0,0 +1,72 @@ +const puppeteer = require("puppeteer"); +if (puppeteer.executablePath().indexOf("/home/ukrbublik/") == 0) { + // ignore for my local dev +} else { + process.env.CHROME_BIN = puppeteer.executablePath(); +} +process.env.TZ = "Etc/UTC"; +process.env.BABEL_ENV = "test"; // Set the proper environment for babel + +module.exports = function(config) { + config.set({ + basePath: "", + frameworks: ["mocha", "chai", "es6-shim"], + plugins: [ + "karma-mocha", + "karma-chai", + "karma-es6-shim", + "karma-chrome-launcher", + "karma-sourcemap-loader", + "karma-webpack", + "karma-mocha-reporter", + "karma-coverage", + ], + + files: [ + { + pattern: "karma.tests.js", + watched: true, + served: true, + included: true, + }, + ], + exclude: [], + preprocessors: { + "karma.tests.js": ["webpack", "sourcemap"], + "../modules/**/*": ["coverage"] + }, + webpack: require("./webpack.config"), + webpackMiddleware: { + stats: "errors-only" + }, + + reporters: ["progress", "coverage"], + + coverageReporter: { + dir: "../coverage", + reporters: [ + { type: "html", subdir: "html" }, + { type: "text-summary" }, + { type: "lcov" } + ], + includeAllSources: true, + instrumenterOptions: { + istanbul: { noCompact: true } + } + }, + + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: false, + browsers: ["ChromeHeadlessNoSandbox"], + customLaunchers: { + ChromeHeadlessNoSandbox: { + base: "ChromeHeadless", + flags: ["--no-sandbox"] + } + }, + singleRun: true, + concurrency: 1 + }); +}; diff --git a/tests/karma.tests.js b/tests/karma.tests.js new file mode 100644 index 000000000..56414c5bc --- /dev/null +++ b/tests/karma.tests.js @@ -0,0 +1,7 @@ +import Enzyme from "enzyme"; +import Adapter from "enzyme-adapter-react-16"; + +Enzyme.configure({adapter: new Adapter()}); + +const context = require.context("./specs", true, /\.test\.[tj]s$/); +context.keys().forEach(context); diff --git a/tests/Basic.test.js b/tests/specs/Basic.test.ts similarity index 88% rename from tests/Basic.test.js rename to tests/specs/Basic.test.ts index de0f7f0bf..0914f1a2d 100644 --- a/tests/Basic.test.js +++ b/tests/specs/Basic.test.ts @@ -1,8 +1,10 @@ import { Query, Builder, BasicConfig } from "react-awesome-query-builder"; import AntdConfig from "react-awesome-query-builder/config/antd"; -import * as configs from "./configs"; -import * as inits from "./inits"; -import { with_qb, empty_value, export_checks } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { with_qb, empty_value, export_checks } from "../support/utils"; +import { expect } from "chai"; +import { ReactWrapper } from "enzyme"; // warning: don't put `export_checks` inside `it` @@ -20,25 +22,25 @@ describe("basic query", () => { describe("import", () => { it("should work with empty value", () => { - with_qb(configs.simple_with_number, empty_value, "default", (qb) => { + with_qb(configs.simple_with_number, empty_value, "default", (qb: ReactWrapper) => { expect(qb.find(".query-builder")).to.have.length(1); }); }); it("should work with empty JsonLogic tree", () => { - with_qb(configs.simple_with_number, undefined, "JsonLogic", (qb) => { + with_qb(configs.simple_with_number, undefined, "JsonLogic", (qb: ReactWrapper) => { expect(qb.find(".query-builder")).to.have.length(1); }); }); it("should work with simple value", () => { - with_qb(configs.simple_with_number, inits.tree_with_number, "default", (qb) => { + with_qb(configs.simple_with_number, inits.tree_with_number, "default", (qb: ReactWrapper) => { expect(qb.find(".query-builder")).to.have.length(1); }); }); it("should work with simple value in JsonLogic format", () => { - with_qb(configs.simple_with_number, inits.with_number, "JsonLogic", (qb) => { + with_qb(configs.simple_with_number, inits.with_number, "JsonLogic", (qb: ReactWrapper) => { expect(qb.find(".query-builder")).to.have.length(1); }); }); diff --git a/tests/ChangeQueryProps.test.js b/tests/specs/ChangeQueryProps.test.js similarity index 89% rename from tests/ChangeQueryProps.test.js rename to tests/specs/ChangeQueryProps.test.js index 836f75848..f849f275c 100644 --- a/tests/ChangeQueryProps.test.js +++ b/tests/specs/ChangeQueryProps.test.js @@ -1,7 +1,7 @@ import { BasicConfig } from "react-awesome-query-builder"; -import * as configs from "./configs"; -import * as inits from "./inits"; -import { with_qb, load_tree } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { with_qb, load_tree } from "../support/utils"; describe("change props", () => { diff --git a/tests/DragAndDrop.test.js b/tests/specs/DragAndDrop.test.js similarity index 97% rename from tests/DragAndDrop.test.js rename to tests/specs/DragAndDrop.test.js index e87e01a51..02f9c6d08 100644 --- a/tests/DragAndDrop.test.js +++ b/tests/specs/DragAndDrop.test.js @@ -1,7 +1,7 @@ import sinon from "sinon"; -import * as configs from "./configs"; -import * as inits from "./inits"; -import { with_qb, simulate_drag_n_drop } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { with_qb, simulate_drag_n_drop } from "../support/utils"; describe("drag-n-drop", () => { diff --git a/tests/InteractionsAntd.test.js b/tests/specs/InteractionsAntd.test.js similarity index 86% rename from tests/InteractionsAntd.test.js rename to tests/specs/InteractionsAntd.test.js index 36b686f3f..ed0c8c718 100644 --- a/tests/InteractionsAntd.test.js +++ b/tests/specs/InteractionsAntd.test.js @@ -1,6 +1,6 @@ -import * as configs from "./configs"; -import * as inits from "./inits"; -import { with_qb_ant } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { with_qb_ant } from "../support/utils"; describe("interactions on antd", () => { diff --git a/tests/specs/InteractionsMaterial.test.js b/tests/specs/InteractionsMaterial.test.js new file mode 100644 index 000000000..eecaa8b89 --- /dev/null +++ b/tests/specs/InteractionsMaterial.test.js @@ -0,0 +1 @@ +//todo: need to check opening datepicker! diff --git a/tests/InteractionsVanilla.test.js b/tests/specs/InteractionsVanilla.test.js similarity index 98% rename from tests/InteractionsVanilla.test.js rename to tests/specs/InteractionsVanilla.test.js index 8f12415a1..45d860401 100644 --- a/tests/InteractionsVanilla.test.js +++ b/tests/specs/InteractionsVanilla.test.js @@ -1,8 +1,8 @@ import { Utils } from "react-awesome-query-builder"; const { getTree } = Utils; -import * as configs from "./configs"; -import * as inits from "./inits"; -import { with_qb } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { with_qb } from "../support/utils"; describe("interactions on vanilla", () => { diff --git a/tests/QueryWithConj.test.js b/tests/specs/QueryWithConj.test.js similarity index 91% rename from tests/QueryWithConj.test.js rename to tests/specs/QueryWithConj.test.js index ac5cdbf7d..b9d85a9f4 100644 --- a/tests/QueryWithConj.test.js +++ b/tests/specs/QueryWithConj.test.js @@ -1,6 +1,6 @@ -import * as configs from "./configs"; -import * as inits from "./inits"; -import { with_qb_skins, export_checks } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { with_qb_skins, export_checks } from "../support/utils"; describe("query with conjunction", () => { diff --git a/tests/QueryWithFieldCompare.test.js b/tests/specs/QueryWithFieldCompare.test.js similarity index 84% rename from tests/QueryWithFieldCompare.test.js rename to tests/specs/QueryWithFieldCompare.test.js index 476f923d9..8c3441181 100644 --- a/tests/QueryWithFieldCompare.test.js +++ b/tests/specs/QueryWithFieldCompare.test.js @@ -1,6 +1,6 @@ -import * as configs from "./configs"; -import * as inits from "./inits"; -import { with_qb_skins, export_checks } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { with_qb_skins, export_checks } from "../support/utils"; describe("query with field compare", () => { diff --git a/tests/QueryWithFunc.test.js b/tests/specs/QueryWithFunc.test.js similarity index 96% rename from tests/QueryWithFunc.test.js rename to tests/specs/QueryWithFunc.test.js index 5f3fcf7df..2689abe83 100644 --- a/tests/QueryWithFunc.test.js +++ b/tests/specs/QueryWithFunc.test.js @@ -1,6 +1,6 @@ -import * as configs from "./configs"; -import * as inits from "./inits"; -import { with_qb, with_qb_ant, export_checks, export_checks_in_it } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { with_qb, with_qb_ant, export_checks, export_checks_in_it } from "../support/utils"; describe("query with func", () => { diff --git a/tests/QueryWithGroupsAndStructs.test.js b/tests/specs/QueryWithGroupsAndStructs.test.js similarity index 98% rename from tests/QueryWithGroupsAndStructs.test.js rename to tests/specs/QueryWithGroupsAndStructs.test.js index 89f9e908b..7b7abf1fb 100644 --- a/tests/QueryWithGroupsAndStructs.test.js +++ b/tests/specs/QueryWithGroupsAndStructs.test.js @@ -1,6 +1,6 @@ -import * as configs from "./configs"; -import * as inits from "./inits"; -import { with_qb_skins, export_checks } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { with_qb_skins, export_checks } from "../support/utils"; describe("query with !struct and !group", () => { diff --git a/tests/QueryWithOperators.test.js b/tests/specs/QueryWithOperators.test.js similarity index 94% rename from tests/QueryWithOperators.test.js rename to tests/specs/QueryWithOperators.test.js index bec953bcd..c6f373abe 100644 --- a/tests/QueryWithOperators.test.js +++ b/tests/specs/QueryWithOperators.test.js @@ -1,6 +1,6 @@ -import * as configs from "./configs"; -import * as inits from "./inits"; -import { export_checks } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { export_checks } from "../support/utils"; describe("query with ops", () => { diff --git a/tests/QueryWithProximity.test.js b/tests/specs/QueryWithProximity.test.js similarity index 82% rename from tests/QueryWithProximity.test.js rename to tests/specs/QueryWithProximity.test.js index ad2edff4a..4b09dff2a 100644 --- a/tests/QueryWithProximity.test.js +++ b/tests/specs/QueryWithProximity.test.js @@ -1,6 +1,6 @@ -import * as configs from "./configs"; -import * as inits from "./inits"; -import { with_qb, export_checks } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { with_qb, export_checks } from "../support/utils"; describe("proximity", () => { diff --git a/tests/QueryWithSubquery.test.js b/tests/specs/QueryWithSubquery.test.js similarity index 94% rename from tests/QueryWithSubquery.test.js rename to tests/specs/QueryWithSubquery.test.js index debe8bec9..edd968e8b 100644 --- a/tests/QueryWithSubquery.test.js +++ b/tests/specs/QueryWithSubquery.test.js @@ -1,6 +1,6 @@ -import * as configs from "./configs"; -import * as inits from "./inits"; -import { with_qb_skins, export_checks } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { with_qb_skins, export_checks } from "../support/utils"; describe("query with subquery and datetime types", () => { diff --git a/tests/RareFeatures.test.js b/tests/specs/RareFeatures.test.js similarity index 93% rename from tests/RareFeatures.test.js rename to tests/specs/RareFeatures.test.js index f534cf2f5..2e44a8291 100644 --- a/tests/RareFeatures.test.js +++ b/tests/specs/RareFeatures.test.js @@ -1,8 +1,8 @@ import { Query, Builder, BasicConfig } from "react-awesome-query-builder"; import AntdConfig from "react-awesome-query-builder/config/antd"; -import * as configs from "./configs"; -import * as inits from "./inits"; -import { with_qb, empty_value, export_checks } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { with_qb, empty_value, export_checks } from "../support/utils"; // warning: don't put `export_checks` inside `it` diff --git a/tests/Validation.test.js b/tests/specs/Validation.test.js similarity index 86% rename from tests/Validation.test.js rename to tests/specs/Validation.test.js index 97b1ae7bb..552129975 100644 --- a/tests/Validation.test.js +++ b/tests/specs/Validation.test.js @@ -1,8 +1,8 @@ import { Utils } from "react-awesome-query-builder"; const { isValidTree } = Utils; -import * as configs from "./configs"; -import * as inits from "./inits"; -import { with_qb } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { with_qb } from "../support/utils"; describe("validation", () => { diff --git a/tests/WidgetsAntd.test.js b/tests/specs/WidgetsAntd.test.js similarity index 98% rename from tests/WidgetsAntd.test.js rename to tests/specs/WidgetsAntd.test.js index 59d99d857..acf674109 100644 --- a/tests/WidgetsAntd.test.js +++ b/tests/specs/WidgetsAntd.test.js @@ -1,7 +1,7 @@ import moment from "moment"; -import * as configs from "./configs"; -import * as inits from "./inits"; -import { with_qb_ant } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { with_qb_ant } from "../support/utils"; describe("antdesign widgets render", () => { diff --git a/tests/WidgetsVanilla.test.js b/tests/specs/WidgetsVanilla.test.js similarity index 96% rename from tests/WidgetsVanilla.test.js rename to tests/specs/WidgetsVanilla.test.js index 8b468643a..a20f042e6 100644 --- a/tests/WidgetsVanilla.test.js +++ b/tests/specs/WidgetsVanilla.test.js @@ -1,6 +1,6 @@ -import * as configs from "./configs"; -import * as inits from "./inits"; -import { with_qb, with_qb_skins } from "./utils"; +import * as configs from "../support/configs"; +import * as inits from "../support/inits"; +import { with_qb, with_qb_skins } from "../support/utils"; describe("vanilla widgets interactions", () => { diff --git a/tests/configs.js b/tests/support/configs.js similarity index 100% rename from tests/configs.js rename to tests/support/configs.js diff --git a/tests/inits.js b/tests/support/inits.js similarity index 100% rename from tests/inits.js rename to tests/support/inits.js diff --git a/tests/utils.js b/tests/support/utils.js similarity index 100% rename from tests/utils.js rename to tests/support/utils.js diff --git a/tests/tsconfig.json b/tests/tsconfig.json new file mode 100644 index 000000000..5f7959ff0 --- /dev/null +++ b/tests/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "es6", + "module": "esnext", + "jsx": "preserve", + "lib": [ + "dom", + "dom.iterable" + ], + "experimentalDecorators": true, + "allowJs": true, + "outDir": "ts_out", + + "strict": true, + "alwaysStrict": true, + "noImplicitReturns": true, + + "esModuleInterop": true, + "moduleResolution": "node", + "baseUrl": "..", + "paths": { + "react-awesome-query-builder": ["modules"], + "react-awesome-query-builder/*": ["modules/*"] + } + }, + "include": [ + "specs/**/*", + "support/**/*" + ] +} diff --git a/webpack-test.config.js b/tests/webpack.config.js similarity index 70% rename from webpack-test.config.js rename to tests/webpack.config.js index fe25ef187..f1b7c9812 100644 --- a/webpack-test.config.js +++ b/tests/webpack.config.js @@ -1,5 +1,9 @@ -var webpack = require('webpack'); -var path = require('path'); +const webpack = require('webpack'); +const path = require('path'); + +const MODULES = path.resolve(__dirname, '../modules/'); +const LibName = 'ReactAwesomeQueryBuilder'; +const lib_name = 'react-awesome-query-builder'; module.exports = { mode: "development", @@ -7,7 +11,7 @@ module.exports = { plugins: [ new webpack.DefinePlugin({ 'process.env': { - NODE_ENV: JSON.stringify('test'), + NODE_ENV: JSON.stringify('development'), CI: JSON.stringify(process.env.CI), }, }), @@ -17,10 +21,7 @@ module.exports = { { test: /\.tsx?$/, use: [{ - loader: 'ts-loader', - options: { - cacheDirectory: true, - }, + loader: 'ts-loader' }], exclude: /node_modules/, }, @@ -29,7 +30,7 @@ module.exports = { use: [{ loader: 'babel-loader', options: { - cacheDirectory: true, + cacheDirectory: true }, }], exclude: /node_modules/ @@ -57,25 +58,26 @@ module.exports = { }, { loader: "less-loader", options: { - javascriptEnabled: true + lessOptions: { + javascriptEnabled: true + } } }] } ], }, - node: { - // Some tests import fs - fs: 'empty', - }, resolve: { extensions: ['.tsx', '.ts', '.js', '.jsx'], modules: [ - 'node_modules', - __dirname + '/node_modules', + 'node_modules' ], alias: { - 'ReactAwesomeQueryBuilder': __dirname + '/modules', - 'react-awesome-query-builder': __dirname + '/modules', + [LibName]: MODULES, + [lib_name]: MODULES, + }, + fallback: { + fs: false, + util: false } }, }; diff --git a/tsconfig.json b/tsconfig.json index 4dcc0acbd..2b387e5ac 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,25 +1,25 @@ { "compilerOptions": { - "target": "es5", + "target": "es6", + "module": "esnext", + "jsx": "preserve", "lib": [ "dom", - "dom.iterable", - "es2017" + "dom.iterable" ], - "esModuleInterop": true, - "moduleResolution": "node", - "sourceMap": true, - "allowJs": true, - "outDir": "./ts_out", - "skipLibCheck": true, - "jsx": "react", - "allowSyntheticDefaultImports": true, "experimentalDecorators": true, - "strictNullChecks": false, - "noImplicitAny": true, - "noUnusedLocals": false, - "noUnusedParameters": false + "allowJs": true, + "outDir": "ts_out", + "noEmit": true, + + "strict": true, + "alwaysStrict": true, + "noImplicitReturns": true, + + "esModuleInterop": true, + "moduleResolution": "node" }, - "include": ["modules"], - "exclude": ["node_modules"] + "include": [ + "modules/**/*" + ] } diff --git a/webpack.config.js b/webpack.config.js index 0ac7bca8a..b9a3e5c09 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,44 +1,56 @@ -var webpack = require('webpack'); -var path = require('path'); -const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; +const webpack = require('webpack'); +const path = require('path'); const CompressionPlugin = require('compression-webpack-plugin'); -//const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); +const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; +const MomentLocalesPlugin = require('moment-locales-webpack-plugin'); -var plugins = [ - new webpack.optimize.OccurrenceOrderPlugin(), +const MODE = process.env.NODE_ENV || "development"; +const BUILD = path.resolve(__dirname, 'build/'); +const MODULES = path.resolve(__dirname, 'modules/'); +const isCompress = process.env.COMPRESS == "1"; +const isAnalyze = process.env.ANALYZE == "1"; +const LibName = 'ReactAwesomeQueryBuilder'; +const lib_name = 'react-awesome-query-builder'; + +let plugins = [ new webpack.DefinePlugin({ - 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV) + 'process.env': { + NODE_ENV: JSON.stringify(MODE), + } }), new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /en|ru|es-us/), + new MomentLocalesPlugin({ + localesToKeep: ['es-us', 'ru'], + }), ]; -var optimization = {}; +let optimization = {}; -if (process.env.ANALYZE == "1") { +if (isCompress) { plugins = [ ...plugins, - new BundleAnalyzerPlugin() + new CompressionPlugin() ]; + optimization.minimize = true; } - -if (process.env.COMPRESS == "1") { +if (isAnalyze) { plugins = [ ...plugins, - new CompressionPlugin() - ]; - optimization.minimizer = [ - //new UglifyJsPlugin() + new BundleAnalyzerPlugin() ]; } module.exports = { plugins, optimization, - mode: process.env.NODE_ENV || "development", + mode: MODE, + entry: [ + './modules/index.js', + ], output: { - library: 'ReactAwesomeQueryBuilder', - libraryTarget: 'umd', - path: path.resolve(__dirname, 'build'), - filename: 'ReactAwesomeQueryBuilder' + (process.env.COMPRESS ? '.min' : '') + '.js', + library: LibName, + libraryTarget: isAnalyze ? undefined : 'umd', + path: BUILD, + filename: LibName + (isCompress ? '.min' : '') + '.js', }, externals: [ { @@ -48,8 +60,8 @@ module.exports = { "redux": "Redux", "immutable": "Immutable", "moment": 'moment', - "sqlstring": "sqlstring", - "classnames": "classnames", + // "sqlstring": "sqlstring", + // "classnames": "classnames", }, /^lodash\/.+$/, ], @@ -63,6 +75,9 @@ module.exports = { { test: /\.jsx?$/, loader: 'babel-loader', + options: { + cacheDirectory: true + }, exclude: /node_modules/ }, { @@ -88,7 +103,9 @@ module.exports = { }, { loader: "less-loader", options: { - javascriptEnabled: true + lessOptions: { + javascriptEnabled: true + } } }] } @@ -97,15 +114,14 @@ module.exports = { resolve: { extensions: ['.tsx', '.ts', '.js', '.jsx'], modules: [ - 'node_modules', - __dirname + '/node_modules', + 'node_modules' ], alias: { - 'ReactAwesomeQueryBuilder': __dirname + '/modules/', - 'immutable': 'immutable' + [LibName]: MODULES, + [lib_name]: MODULES + }, + fallback: { + Buffer: false, } - }, - node: { - Buffer: false } };