diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3dce414 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..eb3f270 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,77 @@ +module.exports = { + "env": { + "browser": true, + "commonjs": true, + "es6": true + }, + "globals": { + "module": true + }, + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "rules": { + "no-multiple-empty-lines": [ + "error", + { + "max": 1 + } + ], + "comma-dangle": [ + "error", + "only-multiline" + ], + "function-paren-newline": [ + "error", + "multiline-arguments" + ], + "no-whitespace-before-property": [ + "error" + ], + "space-infix-ops": [ + "error" + ], + "space-unary-ops": [ + "error" + ], + "rest-spread-spacing": [ + "error", + "never" + ], + "object-property-newline": [ + "error", + { + "allowAllPropertiesOnSameLine": true + } + ], + "no-multi-spaces": [ + "error" + ], + "keyword-spacing": [ + "error" + ], + "object-curly-spacing": [ + "error", + "always", + { + "objectsInObjects": false + } + ], + "space-before-blocks": "error", + "comma-spacing": [ + "error" + ], + "@typescript-eslint/explicit-module-boundary-types": 0, + "@typescript-eslint/no-var-requires": 0, + "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/no-irregular-whitespace": 0 + }, + "plugins": [ + "@typescript-eslint" + ], + "extends": [ + "plugin:@typescript-eslint/recommended" + ], + "parser": "@typescript-eslint/parser" +} \ No newline at end of file diff --git a/.husky/.gitignore b/.husky/.gitignore new file mode 100644 index 0000000..31354ec --- /dev/null +++ b/.husky/.gitignore @@ -0,0 +1 @@ +_ diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 0000000..e8511ea --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npx --no-install commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..d37daa0 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npx --no-install lint-staged diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..0124186 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,40 @@ + +language: node_js +node_js: + - 14 + +env: + - TEST=1 BUILD_NAME=bd + +install: + - npm install + +branches: + only: + - main + - /^ci-.*$/ + +stages: + - test + - name: publish + if: commit_message =~ /release/ + +_shared_build: &bd + script: npm run $BUILD_NAME + if: env(BUILD_NAME) =~ /^\w/ + +jobs: + exclude: + - if: branch = dev OR commit_message =~ /(no-ci)/ + include: + - stage: test + script: npm run test + + - stage: publish + script: npm run $BUILD_NAME + deploy: + provider: npm + api_key: $NPM_API_KEY + email: $EMAIL + on: + branch: main diff --git a/config/jest/cssTransform.js b/config/jest/cssTransform.js new file mode 100644 index 0000000..7ee2d45 --- /dev/null +++ b/config/jest/cssTransform.js @@ -0,0 +1,14 @@ +"use strict"; + +// This is a custom Jest transformer turning style imports into empty objects. +// http://facebook.github.io/jest/docs/tutorial-webpack.html + +module.exports = { + process() { + return "module.exports = {};"; + }, + getCacheKey() { + // The output is always the same. + return "cssTransform"; + }, +}; diff --git a/config/jest/fileTransform.js b/config/jest/fileTransform.js new file mode 100644 index 0000000..1aa0a10 --- /dev/null +++ b/config/jest/fileTransform.js @@ -0,0 +1,12 @@ +"use strict"; + +const path = require("path"); + +// This is a custom Jest transformer turning file imports into filenames. +// http://facebook.github.io/jest/docs/tutorial-webpack.html + +module.exports = { + process(src, filename) { + return `module.exports = ${JSON.stringify(path.basename(filename))};`; + }, +}; diff --git a/config/jest/setup.js b/config/jest/setup.js new file mode 100644 index 0000000..c28ec6d --- /dev/null +++ b/config/jest/setup.js @@ -0,0 +1,7 @@ + +// jest.mock("app/utils", () => { +// return { +// store: {}, // require("../src/app/utils/index"), +// PicFilter: jest.fn(), +// }; +// }); diff --git a/jest.config.js b/jest.config.js index 54ded37..ceb764b 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,37 +1,37 @@ -module.exports = { - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - transformIgnorePatterns: ['\\\\node_modules\\\\'], - - // Automatically clear mock calls and instances between every test - clearMocks: true, - // The directory where Jest should output its coverage files - coverageDirectory: 'coverage', - - // An array of file extensions your modules use - moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx', 'node', 'web.js'], - - // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module - moduleNameMapper: { - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': - "/config/jest/fileTransform.js", - '\\.(css|less)$': "/config/jest/cssTransform.js", - 'app\\/(.*)$': '/src/app/$1', - '@\\/(.*)$': '/src/app/$1', - }, - - // A preset that is used as a base for Jest's configuration - preset: 'ts-jest', - - // The test environment that will be used for testing - testEnvironment: 'node', - setupFiles: [ - // "/config/polyfills.js", - ], - testPathIgnorePatterns: ["scripts"], - transform: { - // "^.+\\.(js|jsx)$": "/node_modules/babel-jest", - "^.+\\.(ts|tsx)$": "/node_modules/ts-jest", - // "^.+\\.css$": "/config/jest/cssTransform.js", - // "^(?!.*\\.(css|json)$)": "/config/jest/fileTransform.js" - }, -} +module.exports = { + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + transformIgnorePatterns: ['node_modules'], + + // Automatically clear mock calls and instances between every test + clearMocks: true, + // The directory where Jest should output its coverage files + coverageDirectory: 'coverage', + + // An array of file extensions your modules use + moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx', 'node', 'web.js'], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + moduleNameMapper: { + '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + "/config/jest/fileTransform.js", + '\\.(css|less)$': "/config/jest/cssTransform.js", + 'app\\/(.*)$': '/src/app/$1', + '@\\/(.*)$': '/src/app/$1', + }, + + // A preset that is used as a base for Jest's configuration + preset: 'ts-jest', + + // The test environment that will be used for testing + testEnvironment: 'node', + setupFiles: [ + // "/config/polyfills.js", + ], + testPathIgnorePatterns: ["scripts"], + transform: { + // "^.+\\.(js|jsx)$": "/node_modules/babel-jest", + "^.+\\.(ts|tsx)$": "/node_modules/ts-jest", + // "^.+\\.css$": "/config/jest/cssTransform.js", + // "^(?!.*\\.(css|json)$)": "/config/jest/fileTransform.js" + }, +} diff --git a/package.json b/package.json index 353b779..f16648d 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,19 @@ "author": "马鹏达", "email": "1251208555@qq.com", "scripts": { - "gen": "yarn tsc --declaration", - "test": "jest --config=jest.config.js" + "bd": "yarn tsc --declaration", + "test": "jest --config=jest.config.js", + "release": "standard-version", + "release:rc": "standard-version --prerelease rc", + "pup": "npm run release && git push --follow-tags origin master", + "pub": "npm run pup && npm publish", + "cz": "cz" }, - "keywords": ["vite", "vite plugin", "commonjs to es module"], + "keywords": [ + "vite", + "vite plugin", + "commonjs to es module" + ], "dependencies": { "@babel/cli": "^7.13.10", "@babel/core": "^7.13.10", @@ -19,10 +28,28 @@ "glob": "^7.1.6" }, "devDependencies": { + "@commitlint/cli": "^12.0.1", + "@commitlint/config-conventional": "^12.0.1", "@types/jest": "^26.0.20", "@types/node": "^14.14.33", + "@typescript-eslint/eslint-plugin": "^4.18.0", + "@typescript-eslint/parser": "^4.18.0", + "babel-jest": "^26.6.3", + "commitizen": "^4.2.3", + "eslint": "^7.22.0", + "husky": "^5.1.3", "jest": "^26.6.3", + "lint-staged": "^10.5.4", + "standard-version": "^9.1.1", "ts-jest": "^26.5.3", "typescript": "^4.2.3" + }, + "lint-staged": { + "*.[jt]sx?": "eslint --fix" + }, + "commitlint": { + "extends": [ + "@commitlint/config-conventional" + ] } -} +} \ No newline at end of file diff --git a/src/utils/base.ts b/src/utils/base.ts index e54323c..dc99fc3 100644 --- a/src/utils/base.ts +++ b/src/utils/base.ts @@ -1,59 +1,59 @@ -import * as parser from "@babel/parser"; -import traverse from "@babel/traverse"; -import generate from "@babel/generator"; -import * as t from '@babel/types' -import { replaceWithDefault, replaceWithProp, replaceWithRequire, replaceWithRest } from "../replace/require"; -import { replaceExports } from "../replace/exports"; -import { getName, getSafe } from "./get"; - -export const visitors = { - VariableDeclaration(path) { - const ctr = path.node.declarations[0] - - try { - if (getSafe(ctr, 'init.property')) { - replaceWithProp(ctr, path); - } else if (ctr.id.type === 'ObjectPattern') { - replaceWithRest(ctr, path) - } else if (getName(ctr, 'init.callee') === 'require') { - replaceWithDefault(ctr, path) - } - } catch(err) { - console.log(err) - } - }, - CallExpression(path) { - if (t.isExpressionStatement(path.parent)) { - replaceWithRequire(path) - } - }, - - // 导出 - AssignmentExpression(path) { - try { - const { node } = path - replaceExports(node, path) - } catch(err) { - console.log(err) - } - }, -} - -export const transformFileBase = (src) => { - try { - const ast = parser.parse(src); - traverse(ast, visitors); - - return generate(ast,); - } catch(err) { - // sourceType 默认为 script,如果报错,则用 module 解析 - const ast = parser.parse(src, { sourceType: "module" }); - traverse(ast, visitors); - - return generate(ast,); - } -} - -export function isCjsFile(content) { - return /(exports[\.\[]|module\.exports|require\()/g.test(content) -} \ No newline at end of file +import * as parser from "@babel/parser"; +import traverse from "@babel/traverse"; +import generate from "@babel/generator"; +import * as t from '@babel/types' +import { replaceWithDefault, replaceWithProp, replaceWithRequire, replaceWithRest } from "../replace/require"; +import { replaceExports } from "../replace/exports"; +import { getName, getSafe } from "./get"; + +export const visitors = { + VariableDeclaration(path) { + const ctr = path.node.declarations[0] + + try { + if (getSafe(ctr, 'init.property')) { + replaceWithProp(ctr, path); + } else if (ctr.id.type === 'ObjectPattern') { + replaceWithRest(ctr, path) + } else if (getName(ctr, 'init.callee') === 'require') { + replaceWithDefault(ctr, path) + } + } catch (err) { + console.log(err) + } + }, + CallExpression(path) { + if (t.isExpressionStatement(path.parent)) { + replaceWithRequire(path) + } + }, + + // 导出 + AssignmentExpression(path) { + try { + const { node } = path + replaceExports(node, path) + } catch (err) { + console.log(err) + } + }, +} + +export const transformFileBase = (src) => { + try { + const ast = parser.parse(src); + traverse(ast, visitors); + + return generate(ast); + } catch (err) { + // sourceType 默认为 script,如果报错,则用 module 解析 + const ast = parser.parse(src, { sourceType: "module" }); + traverse(ast, visitors); + + return generate(ast); + } +} + +export function isCjsFile(content) { + return /(exports[\.\[]|module\.exports|require\()/g.test(content) +} diff --git a/src/utils/get.ts b/src/utils/get.ts index e7eaed5..58bbd8a 100644 --- a/src/utils/get.ts +++ b/src/utils/get.ts @@ -1,19 +1,19 @@ -const reg = /(\w+)\[(\d+)\]/ -type nameType = string | Array - -const _get = (obj: any, names: nameType) => { - let keys = Array.isArray(names) ? names : names.split('.') - -  return keys.reduce((prev, next) => { -    if (reg.test(next)) { -      const [_, name, index] = next.match(reg) -      return prev && prev[name] && prev[name][index] -    } else { -      return prev && prev[next] -    } -  }, obj) -} - -export const getSafe = (obj: any, names: nameType, defaultValue?: any) => _get(obj, names) || defaultValue - -export const getName = (obj: any, names: string, defaultValue?: any) => getSafe(obj, `${names}.name`,) || getSafe(obj, `${names}.value`,) \ No newline at end of file +const reg = /(\w+)\[(\d+)\]/ +type nameType = string | Array + +const _get = (obj: any, names: nameType) => { + const keys = Array.isArray(names) ? names : names.split('.') + +  return keys.reduce((prev, next) => { +    if (reg.test(next)) { +      const [, name, index] = next.match(reg) +      return prev && prev[name] && prev[name][index] +    } else { +      return prev && prev[next] +    } +  }, obj) +} + +export const getSafe = (obj: any, names: nameType, defaultValue?: any) => _get(obj, names) || defaultValue + +export const getName = (obj: any, names: string) => getSafe(obj, `${names}.name`) || getSafe(obj, `${names}.value`)