diff --git a/.eslintrc b/.eslintrc index ae3b374afb2..6e68c758b10 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,3 +1,156 @@ { - "extends": "@antv/eslint-config" + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint", + "eslint-comments", + "import", + "flowtype", + "jest", + "jsx-a11y", + "prettier", + "promise", + "react", + "react-hooks", + "unicorn" + ], + "extends": [ + "airbnb-base", + "eslint:recommended", + "prettier", + "plugin:@typescript-eslint/recommended", + "plugin:jsx-a11y/recommended", + "plugin:import/errors", + "plugin:import/warnings", + "plugin:promise/recommended", + "plugin:prettier/recommended", + "plugin:react/recommended", + "plugin:react-hooks/recommended" + ], + "env": { + "browser": true, + "commonjs": true, + "es6": true, + "jest": true, + "node": true, + "mocha": true, + "jasmine": true + }, + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true + }, + "requireConfigFile": false + }, + "settings": { + "react": { + "version": "detect" + } + }, + "rules": { + "no-bitwise": 0, + "no-continue": 0, + "no-lonely-if": 0, + "no-multi-assign": 0, + "no-nested-ternary": 0, + "no-inner-declarations": 0, + "no-unused-expressions": 0, + "max-classes-per-file": 0, + "prefer-destructuring": 0, + "class-methods-use-this": 0, + "implicit-arrow-linebreak": 0, + "lines-between-class-members": 0, + "@typescript-eslint/lines-between-class-members": 0, + "consistent-return": 0, + "no-return-assign": [2, "except-parens"], + "no-param-reassign": [ + 2, + { + "props": false + } + ], + "no-cond-assign": [2, "except-parens"], + "no-console": [ + 2, + { + "allow": ["warn", "error"] + } + ], + "@typescript-eslint/no-unused-expressions": [ + 2, + { + "allowShortCircuit": true, + "allowTernary": true + } + ], + "eqeqeq": [ + 2, + "always", + { + "null": "ignore" + } + ], + "func-names": [ + 1, + "never", + { + "generators": "as-needed" + } + ], + "import/export": 0, + "import/no-cycle": 0, + "import/extensions": 0, + "import/no-unresolved": 0, + "import/prefer-default-export": 0, + "import/no-extraneous-dependencies": 0, + "promise/always-return": 0, + "promise/catch-or-return": 0, + "@typescript-eslint/no-namespace": 0, + "@typescript-eslint/no-var-requires": 0, + "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/no-non-null-assertion": 0, + "@typescript-eslint/no-empty-function": 0, + "@typescript-eslint/no-empty-interface": 0, + "@typescript-eslint/explicit-module-boundary-types": 0, + "no-shadow": 0, + "@typescript-eslint/no-shadow": 0, + "camelcase": 0, + "@typescript-eslint/camelcase": 0, + "no-use-before-define": 0, + "@typescript-eslint/no-use-before-define": 0, + "no-useless-constructor": 0, + "@typescript-eslint/no-useless-constructor": 0, + "no-unused-vars": 0, + "@typescript-eslint/no-unused-vars": [ + 2, + { + "vars": "all", + "args": "after-used", + "ignoreRestSiblings": true + } + ], + "no-redeclare": 0, + "@typescript-eslint/no-redeclare": [ + 2, + { + "ignoreDeclarationMerge": true + } + ], + "react/sort-comp": 0, + "react/prop-types": 0, + "react/jsx-props-no-spreading": 0, + "react/destructuring-assignment": 0, + "react/no-access-state-in-setstate": 0 + }, + "overrides": [ + { + "files": ["**/*.js"], + "rules": { + "no-console": 0, + "global-require": 0 + } + } + ] } diff --git a/.stylelintrc b/.stylelintrc index 1145ccadd6b..64fb0e09263 100755 --- a/.stylelintrc +++ b/.stylelintrc @@ -1,3 +1,20 @@ { - "extends": ["@antv/stylelint-config"] + "extends": [ + "stylelint-config-standard", + "stylelint-config-rational-order", + "stylelint-config-prettier" + ], + "plugins": [ + "stylelint-order", + "stylelint-declaration-block-no-ignored-properties" + ], + "rules": { + "block-no-empty": null, + "function-name-case": "lower", + "comment-empty-line-before": null, + "no-invalid-double-slash-comments": null, + "no-descending-specificity": null, + "declaration-empty-line-before": null, + "no-duplicate-selectors": null + } } diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 00000000000..203abb21d05 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,117 @@ +const cpuCount = require('os').cpus().length +const es6Transform = require('karma-typescript-es6-transform') + +module.exports = function (config, base, karmaTypescriptConfig) { + const hasFlag = (flag) => process.argv.some((arg) => arg === flag) + const isDebug = hasFlag('--debug') + const isWatch = hasFlag('--auto-watch') + + const common = { + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '.', + + // list of files to exclude + exclude: [], + + plugins: [ + 'jasmine-core', + 'karma-jasmine', + 'karma-typescript', + 'karma-spec-reporter', + 'karma-chrome-launcher', + ], + + frameworks: ['jasmine', 'karma-typescript'], + + preprocessors: { + '**/*.ts': ['karma-typescript'], + }, + + reporters: ['spec', 'karma-typescript'], + + specReporter: { + suppressPassed: isWatch || isDebug, + }, + + browsers: [process.env.CI ? 'ChromeHeadless' : 'ChromeHeadless'], + + customLaunchers: { + ChromeHeadless: { + base: 'Chrome', + flags: [ + '--headless', + '--no-sandbox', + '--disable-gpu', + '--disable-translate', + '--disable-extensions', + '--remote-debugging-port=9222', + ], + }, + }, + + client: { + jasmine: { + random: false, + }, + }, + + // web server port + port: 9876, + + // enable / disable colors in the output (reporters and logs) + colors: true, + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: true, + + // Concurrency level + // how many browser should be started simultaneous + concurrency: cpuCount || Infinity, + } + + const reportsDir = 'test/coverage' + + config.set( + Object.assign(common, base, { + karmaTypescriptConfig: { + tsconfig: 'tsconfig.json', + include: ['./src/**/*.ts'], + bundlerOptions: { + sourceMap: true, + transforms: [ + es6Transform({ + presets: [['@babel/preset-env']], + }), + ], + }, + coverageOptions: { + instrumentation: !isDebug, + exclude: /\.test|spec\.ts$/, + }, + reports: { + html: reportsDir, + lcovonly: { + directory: reportsDir, + subdirectory: './', + filename: 'lcov.info', + }, + cobertura: { + directory: reportsDir, + subdirectory: './', + filename: 'coverage.xml', + }, + 'text-summary': '', + }, + ...karmaTypescriptConfig, + }, + }), + ) +} diff --git a/rollup.config.mjs b/rollup.config.mjs new file mode 100644 index 00000000000..240cb26c159 --- /dev/null +++ b/rollup.config.mjs @@ -0,0 +1,128 @@ +import fs from 'fs' +import path from 'path' +import _ from 'lodash' +import boxen from 'boxen' +import colors from 'colors/safe.js' +import { terser } from 'rollup-plugin-terser' +import replace from '@rollup/plugin-replace' +import resolve from '@rollup/plugin-node-resolve' +import commonjs from '@rollup/plugin-commonjs' +import filesize from 'rollup-plugin-filesize' +import typescript from '@rollup/plugin-typescript' + +function formatName(name) { + const realName = name + .replace(/^@/, '') + .replace(/^antv\//, '') + .replace(/\//, '-') + + // PascalCase + return _.startCase(_.camelCase(realName)).replace(/ /g, '') +} + +function makeOutput() { + const cwd = process.cwd() + const pkg = JSON.parse( + fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'), + ) + const peerDependencies = pkg.peerDependencies + const output = { name: formatName(pkg.name) } + if (peerDependencies) { + const globals = {} + Object.keys(peerDependencies).forEach((mod) => { + globals[mod] = formatName(mod) + }) + output.globals = globals + } + + return output +} + +export function config(config) { + let { plugins = [], output, external = [], ...others } = config || {} + if (output == null) { + output = makeOutput() + } + + const arr = Array.isArray(output) ? output : [output] + const outputs = [] + arr.forEach((item) => { + outputs.push({ + format: 'umd', + file: 'dist/index.js', + sourcemap: true, + ...item, + }) + + // extra external modules + if (item.globals) { + Object.keys(item.globals).forEach((key) => { + if (!external.includes(key)) { + external.push(key) + } + }) + } + }) + + return { + input: './src/index.ts', + output: outputs, + plugins: [ + typescript({ declaration: false }), + resolve(), + commonjs(), + replace({ + preventAssignment: true, + 'process.env.NODE_ENV': JSON.stringify('production'), + }), + terser(), + filesize({ + reporter: [ + function (options, bundle, result) { + const primaryColor = options.theme === 'dark' ? 'green' : 'black' + const secondaryColor = options.theme === 'dark' ? 'yellow' : 'blue' + + const title = colors[primaryColor].bold + const value = colors[secondaryColor] + + const lines = [ + `${title('Bundle Format:')} ${value(bundle.format)}`, + `${title('Bundle Name:')} ${value(bundle.name)}`, + ] + const globals = bundle.globals + const mods = Object.keys(globals) + if (mods.length) { + lines.push(title('External Globals:')) + mods.forEach((mod) => { + lines.push(value(` ${mod}: ${globals[mod]}`)) + }) + lines.push('') + } + + lines.push( + [ + `${title('Destination:')} ${value(bundle.file)}`, + `${title('Bundle Size:')} ${value(result.bundleSize)}`, + `${title('Minified Size:')} ${value(result.minSize)}`, + `${title('Gzipped Size:')} ${value(result.gzipSize)}`, + ].join('\n'), + ) + + return boxen(lines.join('\n'), { + padding: 1, + dimBorder: true, + borderStyle: 'classic', + }) + }, + ], + }), + ...plugins, + ], + external, + ...others, + } +} + +const defaultConfig = config() + +export default defaultConfig