├── .browserslistrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github └── auto-comment.yml ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── babel.config.js ├── check-size.js ├── index.html ├── jest.config.js ├── package.json ├── public ├── favicon.ico ├── index.html └── robots.txt ├── publish-demo.js ├── renovate.json ├── src ├── App.vue ├── assets │ └── logo.png ├── lib │ ├── VueStringFilter.ts │ ├── append.ts │ ├── capitalize.ts │ ├── cut.ts │ ├── index.ts │ ├── lowercase.ts │ ├── remove-first.ts │ ├── remove.ts │ ├── replace-first.ts │ ├── replace.ts │ ├── slug.ts │ ├── titlecase.ts │ ├── truncate.ts │ ├── uppercase.ts │ └── utils.ts ├── main.ts ├── router │ └── index.ts ├── shims-tsx.d.ts ├── shims-vue.d.ts ├── store │ └── index.ts └── views │ └── Home.vue ├── tests └── unit │ ├── filters.spec.ts │ ├── index.d.ts │ ├── utils │ └── index.ts │ └── vue-string-filter.spec.ts ├── tsconfig.json ├── types └── shims-vue.d.ts ├── vue.config.js └── yarn.lock /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # Ignore build directory 2 | dist/* 3 | libs/* 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | 4 | env: { 5 | node: true 6 | }, 7 | 8 | 'extends': [ 9 | 'plugin:vue/essential', 10 | '@vue/standard', 11 | '@vue/typescript' 12 | ], 13 | 14 | rules: { 15 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 16 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 17 | 'no-tabs': 'off', 18 | "@typescript-eslint/camelcase": "off", 19 | "@typescript-eslint/no-empty-interface": "off", 20 | 'no-useless-constructor': 'off', 21 | 'no-unused-vars': 'warn', 22 | 'no-undef': 'off', 23 | 'no-new': 'off', 24 | 'eol-last': 'off' 25 | }, 26 | 27 | parserOptions: { 28 | parser: '@typescript-eslint/parser' 29 | }, 30 | 31 | overrides: [ 32 | { 33 | files: [ 34 | '**/__tests__/*.{j,t}s?(x)', 35 | '**/tests/unit/**/*.spec.{j,t}s?(x)' 36 | ], 37 | env: { 38 | jest: true 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /.github/auto-comment.yml: -------------------------------------------------------------------------------- 1 | pullRequestOpened: > 2 | Thank you for raising your pull request. 3 | Please make sure you have followed @mazipan 4 | And please push ⭐ button in this repository 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | libs/ 61 | dist/ 62 | demo/ 63 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: linux 2 | language: node_js 3 | node_js: '12' 4 | branches: 5 | only: 6 | - master 7 | - /^greenkeeper/.*$/ 8 | cache: 9 | yarn: true 10 | directories: 11 | - node_modules 12 | install: 13 | - yarn install 14 | script: 15 | - yarn test:unit 16 | - yarn build:lib 17 | - yarn check:size 18 | - yarn build:demo 19 | after_script: 20 | - npm install -g codecov 21 | - codecov 22 | deploy: 23 | provider: pages 24 | skip_cleanup: true 25 | token: $GITHUB_TOKEN 26 | keep_history: true 27 | local_dir: demo 28 | verbose: true 29 | on: 30 | branch: master 31 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Vue Currency Filter 2 | 3 | Looking to contribute something? **Here's how you can help.** 4 | 5 | Please take a moment to review this document in order to make the contribution process easy and effective for everyone in the community. 6 | 7 | ## Using the issue tracker 8 | 9 | The issue tracker is the preferred channel for [bug reports](#bug-reports), [features requests](#feature-requests) and [submitting pull requests](#pull-requests), but please respect the following 10 | restrictions: 11 | 12 | * Please **do not** use the issue tracker for personal support requests. Please [email me](mailto:mazipanneh@gmail.com) or [send me a tweet](https://twitter.com/Maz_Ipan) as they are better places to get help. 13 | 14 | * Please **do not** derail or troll issues. Keep the discussion on topic and respect the opinions of others. 15 | 16 | ## Bug reports 17 | 18 | A bug is a _demonstrable problem_ that is caused by the code in the repository. Good bug reports are extremely helpful, so thanks! 19 | 20 | Guidelines for bug reports: 21 | 22 | 1. **Use the GitHub issue search** — check if the issue has already been reported. 23 | 24 | 2. **Check if the issue has been fixed** — try to reproduce it using the latest `master` or development branch in the repository. 25 | 26 | 3. **Isolate the problem** — ideally create a [reduced test case](https://css-tricks.com/reduced-test-cases/). 27 | 28 | 29 | A good bug report shouldn't leave others needing to chase you up for more information. Please try to be as detailed as possible in your report. What is your environment? What steps will reproduce the issue? What browser(s) and OS experience the problem? Do other browsers show the bug differently? What would you expect to be the outcome? All these details will help people to fix any potential bugs. 30 | 31 | Example: 32 | 33 | > Short and descriptive example bug report title 34 | > 35 | > A summary of the issue and the browser/OS environment in which it occurs. If 36 | > suitable, include the steps required to reproduce the bug. 37 | > 38 | > 1. This is the first step 39 | > 2. This is the second step 40 | > 3. Further steps, etc. 41 | > 42 | > `` - a link to the reduced test case 43 | > 44 | > Any other information you want to share that is relevant to the issue being 45 | > reported. This might include the lines of code that you have identified as 46 | > causing the bug, and potential solutions (and your opinions on their 47 | > merits). 48 | 49 | 50 | ## Feature requests 51 | 52 | Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It's up to *you* to make a strong case to convince the project's developers of the merits of this feature. Please provide as much detail and context as possible. 53 | 54 | 55 | ## Pull requests 56 | 57 | Good pull requests—patches, improvements, new features—are a fantastic help. They should remain focused in scope and avoid containing unrelated commits. 58 | 59 | **Please ask first** before embarking on any significant pull request (e.g. implementing features, refactoring code, porting to a different language), otherwise you risk spending a lot of time working on something that the project's developers might not want to merge into the project. 60 | 61 | Please adhere to the [coding guidelines](#code-guidelines) used throughout the project (indentation, accurate comments, etc.) and any other requirements (such as test coverage). 62 | 63 | Adhering to the following process is the best way to get your work included in the project: 64 | 65 | 1. [Fork](https://help.github.com/fork-a-repo/) the project, clone your fork, 66 | and configure the remotes: 67 | 68 | ```bash 69 | # Clone your fork of the repo into the current directory 70 | git clone https://github.com// 71 | # Navigate to the newly cloned directory 72 | cd 73 | # Assign the original repo to a remote called "upstream" 74 | git remote add upstream https://github.com/mazipan/vue-string-filter 75 | ``` 76 | 77 | 2. If you cloned a while ago, get the latest changes from upstream: 78 | 79 | ```bash 80 | git checkout master 81 | git pull upstream master 82 | ``` 83 | 84 | 3. Create a new topic branch (off the main project development branch) to 85 | contain your feature, change, or fix: 86 | 87 | ```bash 88 | git checkout -b 89 | ``` 90 | 91 | 4. Make sure to update, or add to the tests when appropriate. **Patches and 92 | features will not be accepted without tests.** Run `npm test` to check that 93 | all tests pass after you've made changes. 94 | 95 | 5. Locally merge (or rebase) the upstream development branch into your topic branch: 96 | 97 | ```bash 98 | git pull [--rebase] upstream master 99 | ``` 100 | 101 | 6. Push your topic branch up to your fork: 102 | 103 | ```bash 104 | git push origin 105 | ``` 106 | 107 | 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) 108 | with a clear title and description against the `master` branch. 109 | 110 | **IMPORTANT**: By submitting a patch, you agree to allow the project owners to 111 | license your work under the terms of the [MIT License](LICENSE). 112 | 113 | 114 | ## Code guidelines 115 | 116 | ### HTML 117 | 118 | - Use tags and elements appropriate for an HTML5 doctype (e.g., self-closing tags). 119 | 120 | ### JS 121 | 122 | - No semicolons (in client-side JS) 123 | - 2 spaces (no tabs) 124 | - Don't use jQuery (no "$" allowed) 125 | 126 | ### Checking code 127 | 128 | Run `npm run dev` before committing to ensure your changes follow our coding standards. 129 | 130 | 131 | ## License 132 | 133 | By contributing your code, you agree to license your contribution under the [MIT License](LICENSE). -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Irfan Maulana 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :scissors: Vue String Filter 2 | 3 | > Lightweight Vue filter for string manipulation 4 | 5 | [![License](https://img.shields.io/github/license/mazipan/vue-string-filter.svg?maxAge=3600)](https://github.com/mazipan/vue-string-filter) ![minified](https://badgen.net/bundlephobia/minzip/vue-string-filter) [![version](https://img.shields.io/npm/v/vue-string-filter.svg)](https://www.npmjs.com/package/vue-string-filter) [![downloads](https://img.shields.io/npm/dt/vue-string-filter.svg)](https://www.npmjs.com/package/vue-string-filter) [![Travis](https://img.shields.io/travis/mazipan/vue-string-filter.svg)](https://travis-ci.org/mazipan/vue-string-filter) [![codecov](https://codecov.io/gh/mazipan/vue-string-filter/branch/master/graph/badge.svg)](https://codecov.io/gh/mazipan/vue-string-filter) 6 | 7 | ## Demo 8 | 9 | [https://mazipan.github.io/vue-string-filter/](https://mazipan.github.io/vue-string-filter/) 10 | 11 | ## Available Filter 12 | 13 | + `uppercase` 14 | + `lowercase` 15 | + `capitalize` 16 | + `titlecase` 17 | + `slug` 18 | + `truncate` 19 | + `cut` 20 | + `remove` 21 | + `remove_first` 22 | + `replace` 23 | + `replace_first` 24 | + `append` 25 | 26 | ## Download 27 | 28 | ```bash 29 | # NPM 30 | npm install vue-string-filter 31 | 32 | # Yarn 33 | yarn add vue-string-filter 34 | ``` 35 | 36 | ## Sample Usage 37 | 38 | ### Use Plugins 39 | 40 | ```javascript 41 | import VueStringFilter from 'vue-string-filter' 42 | Vue.use(VueStringFilter) 43 | ``` 44 | 45 | #### Import Individual Filters 46 | 47 | ```javascript 48 | import Vue from 'vue' 49 | 50 | // using named exports 51 | import { append, capitalize, cut... } from 'vue-string-filter' 52 | 53 | // directly 54 | import append from 'vue-string-filter/dist/append' 55 | import capitalize from 'vue-string-filter/dist/capitalize' 56 | import cut from 'vue-string-filter/dist/cut' 57 | import lowercase from 'vue-string-filter/dist/lowercase' 58 | import remove_first from 'vue-string-filter/dist/remove-first' 59 | import remove from 'vue-string-filter/dist/remove' 60 | import replace_first from 'vue-string-filter/dist/replace-first' 61 | import replace from 'vue-string-filter/dist/replace' 62 | import slug from 'vue-string-filter/dist/slug' 63 | import titlecase from 'vue-string-filter/dist/titlecase' 64 | import truncate from 'vue-string-filter/dist/truncate' 65 | import uppercase from 'vue-string-filter/dist/uppercase' 66 | 67 | Vue.filter('append', append) 68 | Vue.filter('capitalize', capitalize) 69 | Vue.filter('cut', cut) 70 | Vue.filter('lowercase', lowercase) 71 | Vue.filter('remove_first', remove_first) 72 | Vue.filter('remove', remove) 73 | Vue.filter('replace_first', replace_first) 74 | Vue.filter('replace', replace) 75 | Vue.filter('slug', slug) 76 | Vue.filter('titlecase', titlecase) 77 | Vue.filter('truncate', truncate) 78 | Vue.filter('uppercase', uppercase) 79 | ``` 80 | 81 | ### Use in View 82 | 83 | ```html 84 | {{ stringWillFormatted | uppercase }} 85 | {{ stringWillFormatted | lowercase }} 86 | {{ stringWillFormatted | capitalize }} 87 | {{ stringWillFormatted | titlecase }} 88 | {{ stringWillFormatted | slug }} 89 | {{ stringWillFormatted | truncate(10) }} 90 | {{ stringWillFormatted | cut(10) }} 91 | {{ stringWillFormatted | remove('stringToRemove') }} 92 | {{ stringWillFormatted | remove_first('stringToRemove') }} 93 | {{ stringWillFormatted | replace('stringToReplace') }} 94 | {{ stringWillFormatted | replace_first('stringToReplace') }} 95 | {{ stringWillFormatted | append('stringToAppend') }} 96 | ``` 97 | 98 | ## Support me 99 | 100 | - Via [trakteer](https://trakteer.id/mazipan) 101 | - Direct support, [send me an email](mailto:mazipanneh@gmail.com) 102 | 103 | ## Contributing 104 | 105 | If you'd like to contribute, head to the [contributing guidelines](/CONTRIBUTING.md). Inside you'll find directions for opening issues, coding standards, and notes on development. 106 | 107 | ------ 108 | 109 | Copyright © 2019 Built with ❤️ by Irfan Maulana 110 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /check-size.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const gzipSize = require('gzip-size') 4 | const bytes = require('bytes') 5 | const chalk = require('chalk') 6 | 7 | const SKIP_FILES = ['.gitkeep'] 8 | 9 | function readDirs (dirname, onDir, onError) { 10 | fs.readdir(dirname, function (err, filenames) { 11 | if (err) { 12 | onError(err) 13 | return 14 | } 15 | 16 | filenames 17 | .filter(filename => !SKIP_FILES.includes(filename)) 18 | .map(function (filename) { 19 | const isDir = fs.statSync(dirname + '/' + filename).isDirectory() 20 | if (isDir) { 21 | readDirs(dirname + '/' + filename, onDir, onError) 22 | } else { 23 | onDir(dirname + '/' + filename, filename) 24 | } 25 | }) 26 | }) 27 | } 28 | 29 | setTimeout(() => { 30 | readDirs(path.resolve('./dist/'), async (filepath, filename) => { 31 | try { 32 | console.log(chalk.greenBright(`> ${filename}: ${bytes(gzipSize.fileSync(filepath))}`)) 33 | } catch (err) { 34 | console.error(err) 35 | } 36 | }, (err) => { 37 | console.error(err) 38 | }) 39 | }, 1000) 40 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Vue String Filter | Irfan Maulana 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 45 | 46 | 47 | 53 | 54 | 99 | 100 | 101 | 102 | 103 | 106 | 107 |
108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | verbose: true, 3 | collectCoverage: true, 4 | collectCoverageFrom: [ 5 | '!**/lib/index.ts', 6 | '**/lib/*.ts', 7 | '!**/node_modules/**' 8 | ], 9 | coverageDirectory: 'coverage', 10 | preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel', 11 | globals: { 12 | 'ts-jest': { 13 | babelConfig: true 14 | } 15 | }, 16 | moduleNameMapper: { 17 | '^@/(.*)$': '/$1', 18 | '^vue$': 'vue/dist/vue.common.js' 19 | }, 20 | transform: { 21 | '.*\\.(vue)$': 'vue-jest' 22 | }, 23 | snapshotSerializers: ['/node_modules/jest-serializer-vue'] 24 | } 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-string-filter", 3 | "version": "2.1.0", 4 | "private": false, 5 | "description": "Lightweight Vue filter for string manipulation ", 6 | "author": "Irfan Maulana (https://github.com/mazipan/)", 7 | "scripts": { 8 | "serve": "vue-cli-service serve", 9 | "test:unit": "vue-cli-service test:unit", 10 | "test": "vue-cli-service test:unit", 11 | "lint": "vue-cli-service lint --fix", 12 | "build:demo": "cross-env NODE_ENV=production vue-cli-service build --dest demo", 13 | "build:lib": "cross-env NODE_ENV=production tsc ./src/lib/index.ts -m CommonJS --outDir ./dist --declaration", 14 | "check:size": "node ./check-size.js", 15 | "dev": "vue-cli-service serve", 16 | "prepare": "yarn build:lib" 17 | }, 18 | "main": "dist/index.js", 19 | "module": "dist/index.js", 20 | "unpkg": "dist/index.js", 21 | "files": [ 22 | "dist" 23 | ], 24 | "dependencies": { 25 | "vue": "^2.6.11" 26 | }, 27 | "devDependencies": { 28 | "@types/jest": "^26.0.3", 29 | "@types/node": "14.0.14", 30 | "@typescript-eslint/eslint-plugin": "3.5.0", 31 | "@typescript-eslint/parser": "3.5.0", 32 | "@vue/cli-plugin-babel": "4.4.6", 33 | "@vue/cli-plugin-eslint": "4.4.6", 34 | "@vue/cli-plugin-pwa": "4.4.6", 35 | "@vue/cli-plugin-router": "4.4.6", 36 | "@vue/cli-plugin-typescript": "4.4.6", 37 | "@vue/cli-plugin-unit-jest": "^4.4.6", 38 | "@vue/cli-plugin-vuex": "4.4.6", 39 | "@vue/cli-service": "4.4.6", 40 | "@vue/eslint-config-standard": "5.1.2", 41 | "@vue/eslint-config-typescript": "5.0.2", 42 | "@vue/test-utils": "^1.0.3", 43 | "babel-eslint": "10.1.0", 44 | "bulma-dracula": "1.0.4", 45 | "bytes": "3.1.0", 46 | "chalk": "4.1.0", 47 | "core-js": "3.6.5", 48 | "cross-env": "^7.0.2", 49 | "eslint": "7.3.1", 50 | "eslint-plugin-import": "2.22.0", 51 | "eslint-plugin-node": "11.1.0", 52 | "eslint-plugin-promise": "4.2.1", 53 | "eslint-plugin-standard": "4.0.1", 54 | "eslint-plugin-vue": "6.2.2", 55 | "gzip-size": "5.1.1", 56 | "husky": "4.2.5", 57 | "jest": "^26.1.0", 58 | "lint-staged": "10.2.11", 59 | "node-sass": "4.13.1", 60 | "prismjs": "1.24.0", 61 | "register-service-worker": "1.7.1", 62 | "sass-loader": "8.0.0", 63 | "tsc": "latest", 64 | "typescript": "3.9.6", 65 | "vue-class-component": "7.2.3", 66 | "vue-google-adsense": "1.8.3", 67 | "vue-prism-component": "1.2.0", 68 | "vue-property-decorator": "9.0.0", 69 | "vue-router": "3.3.4", 70 | "vue-script2": "2.1.0", 71 | "vue-template-compiler": "2.6.11", 72 | "vuex": "3.5.1" 73 | }, 74 | "peerDependencies": { 75 | "vue": "2.6.11" 76 | }, 77 | "bugs": { 78 | "url": "https://github.com/mazipan/vue-string-filter/issues" 79 | }, 80 | "homepage": "https://mazipan.github.io/vue-currency-filter/", 81 | "husky": { 82 | "hooks": { 83 | "pre-commit": "lint-staged" 84 | } 85 | }, 86 | "jsdelivr": "dist/VueStringFilter.js", 87 | "keywords": [ 88 | "vue string", 89 | "vue string filter", 90 | "vue filter" 91 | ], 92 | "license": "MIT", 93 | "lint-staged": { 94 | "*.{js,vue}": [ 95 | "yarn lint", 96 | "git add" 97 | ] 98 | }, 99 | "repository": { 100 | "type": "git", 101 | "url": "https://github.com/mazipan/vue-string-filter.git" 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazipan/vue-string-filter/51daa71e2dc6442255a8d3524caf19258ae9dbf0/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Vue String Filter | @mazipan 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /publish-demo.js: -------------------------------------------------------------------------------- 1 | const ghpages = require('gh-pages') 2 | const BRANCH = 'gh-pages' 3 | const TODAY = new Date().toLocaleString() 4 | const FOLDER_DIST = 'dist-demo' 5 | 6 | console.log(`start publishing folder ${FOLDER_DIST} to ${BRANCH}`) 7 | 8 | ghpages.publish(FOLDER_DIST, { 9 | branch: BRANCH, 10 | message: `Publishing folder ${FOLDER_DIST} to ${BRANCH} in ${TODAY}` 11 | }, () => { 12 | console.log(`done publishing folder ${FOLDER_DIST} to ${BRANCH}`) 13 | }) 14 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "automerge": true 6 | } 7 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | 22 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mazipan/vue-string-filter/51daa71e2dc6442255a8d3524caf19258ae9dbf0/src/assets/logo.png -------------------------------------------------------------------------------- /src/lib/VueStringFilter.ts: -------------------------------------------------------------------------------- 1 | import lowercase from './lowercase' 2 | import uppercase from './uppercase' 3 | import capitalize from './capitalize' 4 | import titlecase from './titlecase' 5 | import slug from './slug' 6 | import truncate from './truncate' 7 | import cut from './cut' 8 | import remove from './remove' 9 | import removeFirst from './remove-first' 10 | import replace from './replace' 11 | import replaceFirst from './replace-first' 12 | import append from './append' 13 | 14 | class VueStringFilter implements VueStringFilter { 15 | install (Vue) { 16 | Vue.filter('lowercase', lowercase) 17 | 18 | Vue.filter('uppercase', uppercase) 19 | 20 | Vue.filter('capitalize', capitalize) 21 | 22 | Vue.filter('titlecase', titlecase) 23 | 24 | Vue.filter('slug', slug) 25 | 26 | Vue.filter('truncate', truncate) 27 | 28 | Vue.filter('cut', cut) 29 | 30 | Vue.filter('remove', remove) 31 | 32 | Vue.filter('remove_first', removeFirst) 33 | 34 | Vue.filter('replace', replace) 35 | 36 | Vue.filter('replace_first', replaceFirst) 37 | 38 | Vue.filter('append', append) 39 | } 40 | } 41 | 42 | export default new VueStringFilter() 43 | -------------------------------------------------------------------------------- /src/lib/append.ts: -------------------------------------------------------------------------------- 1 | import { isExists } from './utils' 2 | 3 | export default function (value: string, string: string): string { 4 | if (!isExists(value)) { 5 | return '' 6 | } 7 | 8 | return value.toString().concat(string) 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/capitalize.ts: -------------------------------------------------------------------------------- 1 | import { isExists } from './utils' 2 | 3 | export default function (value: string): string { 4 | if (!isExists(value)) { 5 | return '' 6 | } 7 | 8 | return value.charAt(0).toUpperCase() + value.slice(1) 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/cut.ts: -------------------------------------------------------------------------------- 1 | import { isExists } from './utils' 2 | 3 | export default function (value: string, count: number): string { 4 | if (!isExists(value)) { 5 | return '' 6 | } 7 | 8 | return value.length < count ? value : value.slice(0, count) 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import VueStringFilter from './VueStringFilter' 2 | export { default as lowercase } from './lowercase' 3 | export { default as uppercase } from './uppercase' 4 | export { default as capitalize } from './capitalize' 5 | export { default as titlecase } from './titlecase' 6 | export { default as slug } from './slug' 7 | export { default as truncate } from './truncate' 8 | export { default as cut } from './cut' 9 | export { default as remove } from './remove' 10 | export { default as removeFirst } from './remove-first' 11 | export { default as replace } from './replace' 12 | export { default as replaceFirst } from './replace-first' 13 | export { default as append } from './append' 14 | 15 | export default VueStringFilter 16 | -------------------------------------------------------------------------------- /src/lib/lowercase.ts: -------------------------------------------------------------------------------- 1 | import { isExists } from './utils' 2 | 3 | export default function (value: string): string { 4 | if (!isExists(value)) { 5 | return '' 6 | } 7 | 8 | return value.toString().toLowerCase() 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/remove-first.ts: -------------------------------------------------------------------------------- 1 | import { isExists } from './utils' 2 | 3 | export default function (value: string, target: string): string { 4 | if (!isExists(value)) { 5 | return '' 6 | } 7 | 8 | return value.replace(target, '') 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/remove.ts: -------------------------------------------------------------------------------- 1 | import { isExists } from './utils' 2 | 3 | export default function (value: string, target: string): string { 4 | if (!isExists(value)) { 5 | return '' 6 | } 7 | 8 | return value.replace(new RegExp(target, 'g'), '') 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/replace-first.ts: -------------------------------------------------------------------------------- 1 | import { isExists } from './utils' 2 | 3 | export default function (value: string, replacement: string): string { 4 | if (!isExists(value)) { 5 | return '' 6 | } 7 | 8 | return value.replace(value, replacement) 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/replace.ts: -------------------------------------------------------------------------------- 1 | import { isExists } from './utils' 2 | 3 | export default function (value: string, replacement: string): string { 4 | if (!isExists(value)) { 5 | return '' 6 | } 7 | 8 | return value.replace(new RegExp(value, 'g'), replacement) 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/slug.ts: -------------------------------------------------------------------------------- 1 | import { isExists } from './utils' 2 | 3 | export default function (value: string): string { 4 | if (!isExists(value)) { 5 | return '' 6 | } 7 | 8 | return value 9 | .toString() 10 | .toLowerCase() 11 | .trim() 12 | .replace(/&/g, '-and-') 13 | .replace(/[\s\W]/g, '-') 14 | .replace(/--+/g, '-') 15 | .replace(/^-+|-+$/g, '-') 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/titlecase.ts: -------------------------------------------------------------------------------- 1 | import { isExists } from './utils' 2 | 3 | export default function (value: string): string { 4 | if (!isExists(value)) { 5 | return '' 6 | } 7 | 8 | return value.replace(/\w\S*/g, (txt: string): string => { 9 | return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase() 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/truncate.ts: -------------------------------------------------------------------------------- 1 | import { isExists } from './utils' 2 | 3 | export default function (value: string, count: number): string { 4 | if (!isExists(value)) { 5 | return '' 6 | } 7 | 8 | return value.length < count ? value : value.slice(0, count) + '...' 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/uppercase.ts: -------------------------------------------------------------------------------- 1 | import { isExists } from './utils' 2 | 3 | export default function (value: string): string { 4 | if (!isExists(value)) { 5 | return '' 6 | } 7 | 8 | return value.toString().toUpperCase() 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | export function isExists (value: T | undefined | null): value is T { 2 | return (value as T) !== undefined && (value as T) !== null 3 | } 4 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Ads from 'vue-google-adsense' 3 | 4 | import App from './App.vue' 5 | import router from './router' 6 | import store from './store' 7 | 8 | import VueStringFilter from './lib/VueStringFilter' 9 | 10 | const script2 = require('vue-script2') 11 | 12 | Vue.use(script2) 13 | Vue.use(Ads.Adsense) 14 | Vue.use(Ads.InArticleAdsense) 15 | Vue.use(Ads.InFeedAdsense) 16 | 17 | if (process.env.NODE_ENV !== 'production') { 18 | Vue.config.devtools = true 19 | } 20 | 21 | Vue.use(VueStringFilter) 22 | 23 | Vue.config.productionTip = false 24 | 25 | new Vue({ 26 | router, 27 | store, 28 | render: h => h(App) 29 | }).$mount('#app') 30 | -------------------------------------------------------------------------------- /src/router/index.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import Home from '../views/Home.vue' 4 | 5 | Vue.use(VueRouter) 6 | 7 | const routes = [ 8 | { 9 | path: '/', 10 | name: 'home', 11 | component: Home 12 | } 13 | ] 14 | 15 | const router = new VueRouter({ 16 | routes 17 | }) 18 | 19 | export default router 20 | -------------------------------------------------------------------------------- /src/shims-tsx.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { VNode } from 'vue' 2 | 3 | declare global { 4 | namespace JSX { 5 | // tslint:disable no-empty-interface 6 | interface Element extends VNode {} 7 | // tslint:disable no-empty-interface 8 | interface ElementClass extends Vue {} 9 | interface IntrinsicElements { 10 | [elem: string]: any 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import Vue from 'vue' 3 | export default Vue 4 | } 5 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | }, 9 | mutations: { 10 | }, 11 | actions: { 12 | }, 13 | modules: { 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 103 | 104 | 124 | 125 | 149 | -------------------------------------------------------------------------------- /tests/unit/filters.spec.ts: -------------------------------------------------------------------------------- 1 | import lowercase from "../../src/lib/lowercase"; 2 | import uppercase from "../../src/lib/uppercase"; 3 | import capitalize from "../../src/lib/capitalize"; 4 | import titlecase from "../../src/lib/titlecase"; 5 | import slug from "../../src/lib/slug"; 6 | import truncate from "../../src/lib/truncate"; 7 | import cut from "../../src/lib/cut"; 8 | import remove from "../../src/lib/remove"; 9 | import remove_first from "../../src/lib/remove-first"; 10 | import replace from "../../src/lib/replace"; 11 | import replace_first from "../../src/lib/replace-first"; 12 | import append from "../../src/lib/append"; 13 | import { getTextInput } from "./utils"; 14 | 15 | describe("filters", () => { 16 | test("lowercase", () => { 17 | const text: string = lowercase(getTextInput("lowercase")); 18 | expect(text).toBe("string for lowercase filter"); 19 | }); 20 | 21 | test("uppercase", () => { 22 | const text: string = uppercase(getTextInput("uppercase")); 23 | expect(text).toBe("STRING FOR UPPERCASE FILTER"); 24 | }); 25 | 26 | test("capitalize", () => { 27 | const text: string = capitalize(getTextInput("capitalize")); 28 | expect(text).toBe("String for capitalize filter"); 29 | }); 30 | 31 | it("titlecase", () => { 32 | const text: string = titlecase(getTextInput("titlecase")); 33 | expect(text).toBe("String For Titlecase Filter"); 34 | }); 35 | 36 | it("slug", () => { 37 | const text: string = slug(getTextInput("slug")); 38 | expect(text).toBe("string-for-slug-filter"); 39 | }); 40 | 41 | it("truncate", () => { 42 | const text: string = truncate(getTextInput("truncate"), 6); 43 | expect(text).toBe("string..."); 44 | }); 45 | 46 | it("cut", () => { 47 | const text: string = cut(getTextInput("cut"), 6); 48 | expect(text).toBe("string"); 49 | }); 50 | 51 | it("remove", () => { 52 | const text: string = remove(getTextInput("remove"), "remove "); 53 | expect(text).toBe("string for filter"); 54 | }); 55 | 56 | it("remove_first", () => { 57 | const text: string = remove_first( 58 | getTextInput("remove first remove first"), 59 | "remove first " 60 | ); 61 | expect(text).toBe("string for remove first filter"); 62 | }); 63 | 64 | it("replace", () => { 65 | const text: string = replace(getTextInput("replace"), "replaced"); 66 | expect(text).toBe("replaced"); 67 | }); 68 | 69 | it("replace_first", () => { 70 | const text: string = replace_first( 71 | getTextInput("replace first"), 72 | "replaced" 73 | ); 74 | expect(text).toBe("replaced"); 75 | }); 76 | 77 | it("append", () => { 78 | const text: string = append(getTextInput("append"), " is appended"); 79 | expect(text).toBe("string for append filter is appended"); 80 | }); 81 | }); 82 | -------------------------------------------------------------------------------- /tests/unit/index.d.ts: -------------------------------------------------------------------------------- 1 | import { VueConstructor } from "vue"; 2 | 3 | declare global { 4 | namespace NodeJS { 5 | interface Global { 6 | localVue: VueConstructor; 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/unit/utils/index.ts: -------------------------------------------------------------------------------- 1 | import { Component } from "vue"; 2 | 3 | export const getComponent = (filter: string): Component => { 4 | return { 5 | template: `

{{ textInput | ${filter} }}

`, 6 | data() { 7 | return { 8 | textInput: "" 9 | }; 10 | } 11 | }; 12 | }; 13 | 14 | export const getTextInput = (test: string): string => { 15 | return `string for ${test} filter`; 16 | }; 17 | -------------------------------------------------------------------------------- /tests/unit/vue-string-filter.spec.ts: -------------------------------------------------------------------------------- 1 | import { createLocalVue, shallowMount } from "@vue/test-utils"; 2 | 3 | import VueStringFilter from "../../src/lib/VueStringFilter"; 4 | import { VueConstructor } from "vue"; 5 | import { getComponent, getTextInput } from "./utils"; 6 | 7 | describe.skip("vue-string-filter", () => { 8 | 9 | const localVue = createLocalVue(); 10 | localVue.use(VueStringFilter); 11 | 12 | it("lowercase", () => { 13 | const component = getComponent("lowercase") as VueConstructor; 14 | const wrapper = shallowMount(component, { 15 | localVue 16 | }); 17 | 18 | wrapper.setData({ 19 | textInput: getTextInput("LOWERCASE") 20 | }); 21 | 22 | expect(wrapper.html()).toBe("

string for lowercase filter

"); 23 | }); 24 | 25 | it("uppercase", () => { 26 | const component = getComponent("uppercase") as VueConstructor; 27 | const wrapper = shallowMount(component, { 28 | localVue 29 | }); 30 | 31 | wrapper.setData({ 32 | textInput: getTextInput("uppercase") 33 | }); 34 | 35 | expect(wrapper.html()).toBe("

STRING FOR UPPERCASE FILTER

"); 36 | }); 37 | 38 | it("capitalize", () => { 39 | const component = getComponent("capitalize") as VueConstructor; 40 | const wrapper = shallowMount(component, { 41 | localVue 42 | }); 43 | 44 | wrapper.setData({ 45 | textInput: getTextInput("capitalize") 46 | }); 47 | 48 | expect(wrapper.html()).toBe("

String for capitalize filter

"); 49 | }); 50 | 51 | it("titlecase", () => { 52 | const component = getComponent("titlecase") as VueConstructor; 53 | const wrapper = shallowMount(component, { 54 | localVue 55 | }); 56 | 57 | wrapper.setData({ 58 | textInput: getTextInput("titlecase") 59 | }); 60 | 61 | expect(wrapper.html()).toBe("

String For Titlecase Filter

"); 62 | }); 63 | 64 | it("slug", () => { 65 | const component = getComponent("slug") as VueConstructor; 66 | const wrapper = shallowMount(component, { 67 | localVue 68 | }); 69 | 70 | wrapper.setData({ 71 | textInput: getTextInput("slug") 72 | }); 73 | 74 | expect(wrapper.html()).toBe("

string-for-slug-filter

"); 75 | }); 76 | 77 | it("truncate", () => { 78 | const component = getComponent("truncate(6)") as VueConstructor; 79 | const wrapper = shallowMount(component, { 80 | localVue 81 | }); 82 | 83 | wrapper.setData({ 84 | textInput: getTextInput("truncate") 85 | }); 86 | 87 | expect(wrapper.html()).toBe("

string...

"); 88 | }); 89 | 90 | it("cut", () => { 91 | const component = getComponent("cut(6)") as VueConstructor; 92 | const wrapper = shallowMount(component, { 93 | localVue 94 | }); 95 | 96 | wrapper.setData({ 97 | textInput: getTextInput("cut") 98 | }); 99 | 100 | expect(wrapper.html()).toBe("

string

"); 101 | }); 102 | 103 | it("remove", () => { 104 | const component = getComponent(`remove('remove ')`) as VueConstructor; 105 | const wrapper = shallowMount(component, { 106 | localVue 107 | }); 108 | 109 | wrapper.setData({ 110 | textInput: getTextInput("remove") 111 | }); 112 | 113 | expect(wrapper.html()).toBe("

string for filter

"); 114 | }); 115 | 116 | it("remove_first", () => { 117 | const component = getComponent( 118 | `remove_first('remove first ')` 119 | ) as VueConstructor; 120 | const wrapper = shallowMount(component, { 121 | localVue 122 | }); 123 | 124 | wrapper.setData({ 125 | textInput: getTextInput("remove first remove first") 126 | }); 127 | 128 | expect(wrapper.html()).toBe("

string for remove first filter

"); 129 | }); 130 | 131 | it("replace", () => { 132 | const component = getComponent(`replace('replaced')`) as VueConstructor; 133 | const wrapper = shallowMount(component, { 134 | localVue 135 | }); 136 | 137 | wrapper.setData({ 138 | textInput: getTextInput("replace") 139 | }); 140 | 141 | expect(wrapper.html()).toBe("

replaced

"); 142 | }); 143 | 144 | it("replace_first", () => { 145 | const component = getComponent( 146 | `replace_first('replaced')` 147 | ) as VueConstructor; 148 | const wrapper = shallowMount(component, { 149 | localVue 150 | }); 151 | 152 | wrapper.setData({ 153 | textInput: getTextInput("replace first") 154 | }); 155 | 156 | expect(wrapper.html()).toBe("

replaced

"); 157 | }); 158 | 159 | it("append", () => { 160 | const component = getComponent(`append(' is appended')`) as VueConstructor; 161 | const wrapper = shallowMount(component, { 162 | localVue 163 | }); 164 | 165 | wrapper.setData({ 166 | textInput: getTextInput("append") 167 | }); 168 | 169 | expect(wrapper.html()).toBe("

string for append filter is appended

"); 170 | }); 171 | }); 172 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "emitDeclarationOnly": true, 7 | "strict": true, 8 | "jsx": "preserve", 9 | "importHelpers": true, 10 | "moduleResolution": "node", 11 | "noEmit": false, 12 | "noImplicitAny": false, 13 | "strictNullChecks": false, 14 | "experimentalDecorators": true, 15 | "allowJs": true, 16 | "esModuleInterop": true, 17 | "allowSyntheticDefaultImports": true, 18 | "sourceMap": true, 19 | "rootDir": "src/lib", 20 | "outDir": "dist", 21 | "baseUrl": ".", 22 | "types": [ 23 | "node", 24 | "jest" 25 | ], 26 | "lib": [ 27 | "esnext", 28 | "dom", 29 | "dom.iterable", 30 | "scripthost" 31 | ] 32 | }, 33 | "include": [ 34 | "src/lib/**/*.ts", 35 | "src/lib/**/*.tsx", 36 | "src/lib/**/*.vue" 37 | ], 38 | "exclude": [ 39 | "node_modules" 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /types/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.vue" { 2 | import Vue from "vue"; 3 | export default Vue; 4 | } 5 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | publicPath: '/vue-string-filter', 3 | configureWebpack: { 4 | output: { 5 | libraryExport: 'default' 6 | } 7 | } 8 | } 9 | --------------------------------------------------------------------------------