├── .githooks └── pre-commit ├── .github ├── release.yml └── workflows │ └── test.yml ├── .gitignore ├── .prettierignore ├── CHANGELOG.md ├── README.md ├── lerna.json ├── package.json ├── packages ├── @power-doctest │ ├── asciidoctor │ │ ├── .mocharc.json │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ └── index.ts │ │ ├── test │ │ │ ├── snapshot.test.ts │ │ │ ├── snapshots │ │ │ │ ├── another-attribute │ │ │ │ │ ├── input.adoc │ │ │ │ │ └── output.json │ │ │ │ ├── disabled │ │ │ │ │ ├── input.adoc │ │ │ │ │ └── output.json │ │ │ │ ├── enabled │ │ │ │ │ ├── input.adoc │ │ │ │ │ └── output.json │ │ │ │ ├── error │ │ │ │ │ ├── input.adoc │ │ │ │ │ └── output.json │ │ │ │ ├── js │ │ │ │ │ ├── input.adoc │ │ │ │ │ └── output.json │ │ │ │ ├── meta │ │ │ │ │ ├── input.adoc │ │ │ │ │ └── output.json │ │ │ │ ├── options │ │ │ │ │ ├── input.adoc │ │ │ │ │ └── output.json │ │ │ │ ├── simple │ │ │ │ │ ├── input.adoc │ │ │ │ │ └── output.json │ │ │ │ ├── source-include │ │ │ │ │ ├── input.adoc │ │ │ │ │ ├── output.json │ │ │ │ │ └── source.js │ │ │ │ └── with-another-attr │ │ │ │ │ ├── input.adoc │ │ │ │ │ └── output.json │ │ │ └── tsconfig.json │ │ └── tsconfig.json │ ├── core │ │ ├── .gitignore │ │ ├── .mocharc.json │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── inject-assert.ts │ │ │ └── power-doctest.ts │ │ ├── test │ │ │ ├── power-doctest.test.ts │ │ │ ├── snapshot.test.ts │ │ │ ├── snapshots │ │ │ │ ├── async-function │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.js │ │ │ │ ├── bigint │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.js │ │ │ │ ├── console │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.js │ │ │ │ ├── end-semicolon │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.js │ │ │ │ ├── error │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.js │ │ │ │ ├── es2022-top-level-await │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.js │ │ │ │ ├── literal │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.js │ │ │ │ ├── object │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.js │ │ │ │ ├── private-fields │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.js │ │ │ │ ├── promise │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.js │ │ │ │ └── timeout │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.js │ │ │ └── tsconfig.json │ │ └── tsconfig.json │ ├── javascript │ │ ├── .mocharc.json │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ └── index.ts │ │ ├── test │ │ │ ├── snapshot.test.ts │ │ │ ├── snapshots │ │ │ │ ├── disabled │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.json │ │ │ │ ├── enabled │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.json │ │ │ │ ├── expected-error │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.json │ │ │ │ ├── ok.no-assert │ │ │ │ │ ├── error.txt │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.json │ │ │ │ └── ok │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.json │ │ │ └── tsconfig.json │ │ └── tsconfig.json │ ├── markdown │ │ ├── .gitignore │ │ ├── .mocharc.json │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── DocTestController.ts │ │ │ └── index.ts │ │ ├── test │ │ │ ├── fixtures │ │ │ │ └── ng.invalid-options │ │ │ │ │ ├── error.txt │ │ │ │ │ └── input.md │ │ │ ├── snapshot.test.ts │ │ │ ├── snapshots │ │ │ │ ├── ng.async │ │ │ │ │ ├── input.md │ │ │ │ │ └── output.json │ │ │ │ ├── ng.runMode-all-timeout │ │ │ │ │ ├── input.md │ │ │ │ │ ├── options.json │ │ │ │ │ └── output.json │ │ │ │ ├── ng.simple │ │ │ │ │ ├── input.md │ │ │ │ │ └── output.json │ │ │ │ ├── ng.with-meta │ │ │ │ │ ├── input.md │ │ │ │ │ └── output.json │ │ │ │ ├── ok.disable │ │ │ │ │ ├── input.md │ │ │ │ │ └── output.json │ │ │ │ ├── ok.doctest-error │ │ │ │ │ ├── input.md │ │ │ │ │ └── output.json │ │ │ │ ├── ok.runMode-any │ │ │ │ │ ├── input.md │ │ │ │ │ └── output.json │ │ │ │ └── ok.simple │ │ │ │ │ ├── input.md │ │ │ │ │ └── output.json │ │ │ └── tsconfig.json │ │ └── tsconfig.json │ ├── tester │ │ ├── .gitignore │ │ ├── .mocharc.json │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ └── index.ts │ │ ├── test │ │ │ ├── index.test.ts │ │ │ ├── snapshot.test.ts │ │ │ ├── snapshots │ │ │ │ ├── error.array │ │ │ │ │ ├── error.txt │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.json │ │ │ │ ├── error.async │ │ │ │ │ ├── error.txt │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.json │ │ │ │ ├── error.object │ │ │ │ │ ├── error.txt │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.json │ │ │ │ ├── ok.array │ │ │ │ │ ├── error.txt │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.json │ │ │ │ ├── ok.no-assert │ │ │ │ │ ├── error.txt │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.json │ │ │ │ └── ok.private-field │ │ │ │ │ ├── error.txt │ │ │ │ │ ├── input.js │ │ │ │ │ └── output.json │ │ │ └── tsconfig.json │ │ ├── tsconfig.json │ │ └── yarn.lock │ └── types │ │ ├── .mocharc.json │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ └── index.ts │ │ ├── test │ │ ├── index.test.ts │ │ └── tsconfig.json │ │ └── tsconfig.json ├── comment-to-assert │ ├── .gitignore │ ├── .mocharc.json │ ├── .prettierignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── bin │ │ └── cmd.js │ ├── example │ │ ├── example.js │ │ └── package.json │ ├── package.json │ ├── prettier.config.js │ ├── src │ │ ├── ast-utils.ts │ │ └── comment-to-assert.ts │ ├── test │ │ ├── comment-to-assert-test.ts │ │ ├── snapshot-test.ts │ │ ├── snapshots │ │ │ ├── Array-strings │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── Array │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── BinaryExpression │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── BlockComent │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── CallExpression │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── ConsoleLog │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── NaN │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── Number-String │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── Promise.reject │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── Promise.resolve │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── ThrowError-message │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── ThrowError │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── callback.NaN │ │ │ │ ├── input.js │ │ │ │ ├── options.js │ │ │ │ └── output.js │ │ │ ├── callback.multiple-assert │ │ │ │ ├── input.js │ │ │ │ ├── options.js │ │ │ │ └── output.js │ │ │ ├── console.log.Promise.resolve │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── directive-string-prologue │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── multiple-comments │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── no-rewrite-single-var-comment │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── no-rewrite-single-var │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── null-literal │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── number-literal │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── numeric-separator │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── string-literal │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── undefined │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ ├── variable-expeceted-object │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ │ └── variable │ │ │ │ ├── input.js │ │ │ │ └── output.js │ │ └── tsconfig.json │ └── tsconfig.json └── power-doctest │ ├── .mocharc.json │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── bin │ └── cmd.js │ ├── package.json │ ├── src │ ├── cli.ts │ └── power-doctest.ts │ ├── test │ ├── fixture-pkg │ │ ├── index.js │ │ └── package.json │ ├── power-doctest.test.ts │ └── tsconfig.json │ └── tsconfig.json ├── pnpm-lock.yaml └── pnpm-workspace.yaml /.githooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | npx --no-install lint-staged 3 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - 'Type: Meta' 5 | - 'Type: Question' 6 | - 'Type: Release' 7 | 8 | categories: 9 | - title: Security Fixes 10 | labels: ['Type: Security'] 11 | - title: Breaking Changes 12 | labels: ['Type: Breaking Change'] 13 | - title: Features 14 | labels: ['Type: Feature'] 15 | - title: Bug Fixes 16 | labels: ['Type: Bug'] 17 | - title: Documentation 18 | labels: ['Type: Documentation'] 19 | - title: Refactoring 20 | labels: ['Type: Refactoring'] 21 | - title: Testing 22 | labels: ['Type: Testing'] 23 | - title: Maintenance 24 | labels: ['Type: Maintenance'] 25 | - title: CI 26 | labels: ['Type: CI'] 27 | - title: Dependency Updates 28 | labels: ['Type: Dependencies', "dependencies"] 29 | - title: Other Changes 30 | labels: ['*'] 31 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | on: [push, pull_request] 3 | jobs: 4 | test: 5 | name: "Test on Node.js ${{ matrix.node-version }}" 6 | runs-on: ubuntu-latest 7 | strategy: 8 | matrix: 9 | node-version: [ 20, 22 ] 10 | steps: 11 | - name: checkout 12 | uses: actions/checkout@v4 13 | - uses: pnpm/action-setup@v4 14 | - name: setup Node.js ${{ matrix.node-version }} 15 | uses: actions/setup-node@v4 16 | with: 17 | node-version: ${{ matrix.node-version }} 18 | - name: Install 19 | run: | 20 | pnpm install 21 | pnpm run bootstrap 22 | - name: Test 23 | run: pnpm test 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # monorepo 2 | 3 | /packages/**/lib 4 | 5 | ### https://raw.github.com/github/gitignore/d2c1bb2b9c72ead618c9f6a48280ebc7a8e0dff6/Node.gitignore 6 | 7 | # Logs 8 | logs 9 | *.log 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # TypeScript v1 declaration files 46 | typings/ 47 | 48 | # Optional npm cache directory 49 | .npm 50 | 51 | # Optional eslint cache 52 | .eslintcache 53 | 54 | # Optional REPL history 55 | .node_repl_history 56 | 57 | # Output of 'npm pack' 58 | *.tgz 59 | 60 | # Yarn Integrity file 61 | .yarn-integrity 62 | 63 | # dotenv environment variables file 64 | .env 65 | .env.test 66 | 67 | # parcel-bundler cache (https://parceljs.org/) 68 | .cache 69 | 70 | # next.js build output 71 | .next 72 | 73 | # nuxt.js build output 74 | .nuxt 75 | 76 | # vuepress build output 77 | .vuepress/dist 78 | 79 | # Serverless directories 80 | .serverless/ 81 | 82 | # FuseBox cache 83 | .fusebox/ 84 | 85 | # DynamoDB Local files 86 | .dynamodb/ 87 | 88 | 89 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/snapshots/** 2 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "5.3.4", 3 | "npmClient": "pnpm", 4 | "includeMergedTags": true 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "root", 4 | "version": "1.0.0", 5 | "description": "monorepo root", 6 | "main": "index.js", 7 | "devDependencies": { 8 | "lerna": "^8.2.0", 9 | "lint-staged": "^15.4.3", 10 | "prettier": "^3.0.0" 11 | }, 12 | "scripts": { 13 | "bootstrap": "npm run build", 14 | "build": "lerna run build", 15 | "test": "lerna run test", 16 | "updateSnapshot": "lerna run updateSnapshot", 17 | "versionup": "lerna version", 18 | "versionup:patch": "lerna version patch", 19 | "versionup:minor": "lerna version minor", 20 | "versionup:major": "lerna version major", 21 | "release": "lerna publish from-package", 22 | "format": "prettier --write \"**/*.{js,jsx,ts,tsx,css}\"", 23 | "prepare": "git config --local core.hooksPath .githooks" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+ssh://git@github.com/azu/power-doctest.git" 28 | }, 29 | "keywords": [], 30 | "author": "azu", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/azu/power-doctest/issues" 34 | }, 35 | "homepage": "https://github.com/azu/power-doctest", 36 | "prettier": { 37 | "singleQuote": false, 38 | "printWidth": 120, 39 | "tabWidth": 4, 40 | "trailingComma": "none" 41 | }, 42 | "lint-staged": { 43 | "*.{js,jsx,ts,tsx,css}": [ 44 | "prettier --write" 45 | ] 46 | }, 47 | "packageManager": "pnpm@10.5.2+sha512.da9dc28cd3ff40d0592188235ab25d3202add8a207afbedc682220e4a0029ffbff4562102b9e6e46b4e3f9e8bd53e6d05de48544b0c57d4b0179e22c76d1199b" 48 | } 49 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": [ 3 | "ts-node-test-register" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [5.3.3](https://github.com/azu/power-doctest/compare/v5.3.2...v5.3.3) (2023-07-15) 7 | 8 | **Note:** Version bump only for package @power-doctest/asciidoctor 9 | 10 | 11 | 12 | 13 | 14 | ## [5.3.1](https://github.com/azu/power-doctest/compare/v5.3.0...v5.3.1) (2022-01-05) 15 | 16 | 17 | ### Bug Fixes 18 | 19 | * **deps:** Update babel dependencies to ^7.16.7 ([#28](https://github.com/azu/power-doctest/issues/28)) ([92d68cd](https://github.com/azu/power-doctest/commit/92d68cd8100839cf37c409480a3a932290ff2fbe)) 20 | 21 | 22 | 23 | 24 | 25 | # [5.3.0](https://github.com/azu/power-doctest/compare/v5.2.2...v5.3.0) (2021-05-07) 26 | 27 | 28 | ### Features 29 | 30 | * **deps:** support numeric separator ([#26](https://github.com/azu/power-doctest/issues/26)) ([f0ef57b](https://github.com/azu/power-doctest/commit/f0ef57b02e767576dde6a81582025a9f19db1143)) 31 | 32 | 33 | 34 | 35 | 36 | # [5.2.0](https://github.com/azu/power-doctest/compare/v5.1.3...v5.2.0) (2020-06-20) 37 | 38 | 39 | ### Features 40 | 41 | * **power-doctest:** support ES2020 ([ef624cb](https://github.com/azu/power-doctest/commit/ef624cb9312d62a69b72dcbbbff589557f9b93e5)) 42 | 43 | 44 | 45 | 46 | 47 | ## [5.0.1](https://github.com/azu/power-doctest/compare/v5.0.0...v5.0.1) (2019-09-01) 48 | 49 | **Note:** Version bump only for package @power-doctest/asciidoctor 50 | 51 | 52 | 53 | 54 | 55 | # [5.0.0](https://github.com/azu/power-doctest/compare/v4.1.2...v5.0.0) (2019-09-01) 56 | 57 | **Note:** Version bump only for package @power-doctest/asciidoctor 58 | 59 | 60 | 61 | 62 | 63 | ## [4.1.2](https://github.com/azu/power-doctest/compare/v4.1.1...v4.1.2) (2019-09-01) 64 | 65 | **Note:** Version bump only for package @power-doctest/asciidoctor 66 | 67 | 68 | 69 | 70 | 71 | ## [4.1.1](https://github.com/azu/power-doctest/compare/v4.1.0...v4.1.1) (2019-09-01) 72 | 73 | 74 | ### Bug Fixes 75 | 76 | * **asciidoctor:** compute position form string match ([7eedda1](https://github.com/azu/power-doctest/commit/7eedda1)) 77 | 78 | 79 | 80 | 81 | 82 | # [4.0.0](https://github.com/azu/power-doctest/compare/v3.3.3...v4.0.0) (2019-09-01) 83 | 84 | 85 | ### Features 86 | 87 | * **@power-doctest/asciidoctor:** add asciidoctor parser ([ffb3a9e](https://github.com/azu/power-doctest/commit/ffb3a9e)) 88 | * **tester:** add default state ([9fc3aa8](https://github.com/azu/power-doctest/commit/9fc3aa8)) 89 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 azu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/README.md: -------------------------------------------------------------------------------- 1 | # @power-doctest/asciidoctor 2 | 3 | A [Asciidoctor](https://asciidoctor.org/) parser for power-doctest. 4 | 5 | ## Install 6 | 7 | Install with [npm](https://www.npmjs.com/): 8 | 9 | npm install @power-doctest/asciidoctor 10 | 11 | ## Usage 12 | 13 | ## Doctest Control Annotation 14 | 15 | `@power-doctest/asciidoctor` support Doctest Control Annotation as attributes. 16 | 17 | ### Enable Doctest 18 | 19 | Enable doctest for the source code. 20 | 21 | ```asciidoc 22 | [doctest="enabled"] 23 | [source,javascript] 24 | ---- 25 | const str = "string"; 26 | console.log(str); // => "string" 27 | ---- 28 | ``` 29 | 30 | ### Disable Doctest 31 | 32 | Disable doctest for the source code. 33 | 34 | ```asciidoc 35 | [doctest="disabled"] 36 | [source,javascript] 37 | ---- 38 | const str = "string"; 39 | console.log(str); // => "string" 40 | ---- 41 | ``` 42 | 43 | ### Expected error 44 | 45 | If the expected error is not match the result, throw error. 46 | 47 | ```asciidoc 48 | [doctest-error="SyntaxError"] 49 | [source,javascript] 50 | ---- 51 | +++++INVALID SYNTAX++++ 52 | ---- 53 | ``` 54 | 55 | ### Doctest options 56 | 57 | Pass `options` to [@power-doctest/tester](https://www.npmjs.com/package/@power-doctest/tester) 58 | The inline options is preferred constructor options. 59 | 60 | 61 | ```js 62 | if (1 === 1) { 63 | console.log(1); // => 1 64 | } else{ 65 | console.log(2); // => 2 66 | } 67 | ``` 68 | 69 | ### Metadata 70 | 71 | Attach metadata to doctest error of [@power-doctest/tester](https://www.npmjs.com/package/@power-doctest/tester). 72 | It is useful for implementing original behavior. 73 | 74 | 75 | ```asciidoc 76 | [doctest-meta={ "ECMAScript": 2017 }] 77 | [source,javascript] 78 | ---- 79 | const str = "string"; 80 | console.log(str); // => "string" 81 | ---- 82 | ``` 83 | 84 | ## Changelog 85 | 86 | See [Releases page](https://github.com/azu/power-doctest/releases). 87 | 88 | ## Running tests 89 | 90 | Install devDependencies and Run `npm test`: 91 | 92 | npm test 93 | 94 | ## Contributing 95 | 96 | Pull requests and stars are always welcome. 97 | 98 | For bugs and feature requests, [please create an issue](https://github.com/azu/power-doctest/issues). 99 | 100 | 1. Fork it! 101 | 2. Create your feature branch: `git checkout -b my-new-feature` 102 | 3. Commit your changes: `git commit -am 'Add some feature'` 103 | 4. Push to the branch: `git push origin my-new-feature` 104 | 5. Submit a pull request :D 105 | 106 | ## Author 107 | 108 | - [github/azu](https://github.com/azu) 109 | - [twitter/azu_re](https://twitter.com/azu_re) 110 | 111 | ## License 112 | 113 | MIT © azu 114 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@power-doctest/asciidoctor", 3 | "version": "5.3.4", 4 | "description": "A Asciidoctor parser for power-doctest.", 5 | "keywords": [ 6 | "asciidoc", 7 | "asciidoctor", 8 | "doctest" 9 | ], 10 | "homepage": "https://github.com/azu/power-doctest/tree/master/packages/@power-doctest/asciidoctor/", 11 | "bugs": { 12 | "url": "https://github.com/azu/power-doctest/issues" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/azu/power-doctest.git" 17 | }, 18 | "license": "MIT", 19 | "author": "azu", 20 | "files": [ 21 | "bin/", 22 | "lib/", 23 | "src/" 24 | ], 25 | "main": "lib/index.js", 26 | "types": "lib/index.d.ts", 27 | "directories": { 28 | "lib": "lib", 29 | "test": "test" 30 | }, 31 | "scripts": { 32 | "build": "tsc -p .", 33 | "updateSnapshot": "UPDATE_SNAPSHOT=1 npm test", 34 | "clean": "rimraf lib/", 35 | "prettier": "prettier --write \"**/*.{js,jsx,ts,tsx,css}\"", 36 | "prepublish": "npm run --if-present build", 37 | "test": "mocha \"test/**/*.ts\"", 38 | "watch": "tsc -p . --watch" 39 | }, 40 | "prettier": { 41 | "printWidth": 120, 42 | "singleQuote": false, 43 | "tabWidth": 4 44 | }, 45 | "dependencies": { 46 | "@power-doctest/types": "workspace:^", 47 | "asciidoctor": "^3.0.2", 48 | "structured-source": "^4.0.0" 49 | }, 50 | "devDependencies": { 51 | "@types/mocha": "^10.0.1", 52 | "@types/node": "^22.13.8", 53 | "mocha": "^11.1.0", 54 | "prettier": "^3.0.0", 55 | "rimraf": "^6.0.1", 56 | "ts-node": "^10.4.0", 57 | "ts-node-test-register": "^10.0.0", 58 | "typescript": "^5.1.6" 59 | }, 60 | "publishConfig": { 61 | "access": "public" 62 | }, 63 | "gitHead": "f5473fe0c929896882fb8201e23745a9116b1159" 64 | } 65 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/src/index.ts: -------------------------------------------------------------------------------- 1 | import { StructuredSource } from "structured-source"; 2 | import { ParsedCode, ParsedResults, ParserArgs } from "@power-doctest/types"; 3 | import * as fs from "fs"; 4 | import * as path from "path"; 5 | 6 | const Asciidoctor = require("asciidoctor"); 7 | const asciidoctor = Asciidoctor(); 8 | type Attributes = { 9 | [index: string]: string; 10 | }; 11 | const getState = (attributes: Attributes): "none" | "enabled" | "disabled" => { 12 | const state = attributes["doctest-state"] || attributes["doctest"]; 13 | if (!state) { 14 | return "none"; 15 | } 16 | if (/enable(d)?/.test(state)) { 17 | return "enabled"; 18 | } else if (/disable(d)?/.test(state)) { 19 | return "disabled"; 20 | } 21 | return "none"; 22 | }; 23 | 24 | const getExpectedError = (attributes: Attributes): string | undefined => { 25 | const error = attributes["doctest-error"] || attributes["doctest"]; 26 | if (!error) { 27 | return; 28 | } 29 | const pattern = /(\w+Error)/; 30 | const match = error.match(pattern); 31 | if (match && match[1]) { 32 | return match[1]; 33 | } 34 | return; 35 | }; 36 | 37 | const getMeta = (attributes: Attributes): {} | undefined => { 38 | const meta = attributes["doctest-meta"]; 39 | if (!meta) { 40 | return; 41 | } 42 | try { 43 | return JSON.parse(meta); 44 | } catch (error) { 45 | // parse error 46 | throw new Error(`Can not parsed. doctest-meta={...} should be JSON object: ${error}`); 47 | } 48 | }; 49 | 50 | const getOptions = (attributes: Attributes): {} | undefined => { 51 | const meta = attributes["doctest-options"]; 52 | if (!meta) { 53 | return; 54 | } 55 | try { 56 | return JSON.parse(meta); 57 | } catch (error) { 58 | // parse error 59 | throw new Error(`Can not parsed. doctest-options={...} should be JSON object: ${error}`); 60 | } 61 | }; 62 | 63 | // inlining include:: 64 | const inlineCode = (code: string, baseFilePath: string): string => { 65 | // include:: -> link: 66 | const pattern = /link:(.+)\[.*?]/; 67 | const dirName = path.dirname(baseFilePath); 68 | return code.replace(pattern, (all, filePath) => { 69 | const fileName = path.resolve(dirName, filePath); 70 | if (fs.existsSync(fileName)) { 71 | return fs.readFileSync(fileName, "utf-8"); 72 | } 73 | return all; 74 | }); 75 | }; 76 | 77 | export function parse(args: ParserArgs): ParsedResults { 78 | const structuredSource = new StructuredSource(args.content); 79 | const doc = asciidoctor.load(args.content); 80 | return doc 81 | .getBlocks() 82 | .filter((block: any) => { 83 | const attributes = block.getAttributes(); 84 | return ( 85 | attributes.style === "source" && (attributes.language === "js" || attributes.language === "javascript") 86 | ); 87 | }) 88 | .map((block: any) => { 89 | // FIXME: workaround get lineno 90 | // asciidoctor.js does not support lineno for the block 91 | const code: string = block.getSource(); 92 | const index = args.content.indexOf(code); 93 | const startPosition = structuredSource.indexToPosition(index); 94 | const endPosition = structuredSource.indexToPosition(index + code.length); 95 | const attributes: {} = block.getAttributes(); 96 | const meta = getMeta(attributes); 97 | const doctestOptions = getOptions(attributes); 98 | const parsedCode: ParsedCode = { 99 | code: inlineCode(code, args.filePath), 100 | state: getState(attributes), 101 | expectedError: getExpectedError(attributes), 102 | location: { 103 | start: startPosition, 104 | end: endPosition, 105 | }, 106 | metadata: meta, 107 | doctestOptions: doctestOptions 108 | ? { 109 | filePath: args.filePath, 110 | ...doctestOptions, 111 | } 112 | : { 113 | filePath: args.filePath, 114 | }, 115 | }; 116 | return parsedCode; 117 | }); 118 | } 119 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshot.test.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import * as path from "path"; 3 | import * as assert from "assert"; 4 | // transform function 5 | import { parse } from "../src"; 6 | 7 | const fixturesDir = path.join(__dirname, "snapshots"); 8 | 9 | const trimUndefinedProperty = (o: T, baseDir: string): T => { 10 | return JSON.parse(stringify(o as {}, baseDir)); 11 | }; 12 | const stringify = (o: {}, baseDir: string): string => { 13 | return JSON.stringify( 14 | o, 15 | (key: string, value: any) => { 16 | if (key === "filePath" && typeof value === "string") { 17 | return path.relative(baseDir, value); 18 | } else { 19 | return value; 20 | } 21 | }, 22 | 4, 23 | ); 24 | }; 25 | describe("Snapshot testing", () => { 26 | fs.readdirSync(fixturesDir).map((caseName) => { 27 | const normalizedTestName = caseName.replace(/-/g, " "); 28 | it(`Test ${normalizedTestName}`, async function () { 29 | const fixtureDir = path.join(fixturesDir, caseName); 30 | const actualFilePath = path.join(fixtureDir, "input.adoc"); 31 | const actualContent = fs.readFileSync(actualFilePath, "utf-8"); 32 | const results = parse({ 33 | content: actualContent, 34 | filePath: actualFilePath, 35 | }); 36 | const expectedFilePath = path.join(fixtureDir, "output.json"); 37 | // Usage: update snapshots 38 | // UPDATE_SNAPSHOT=1 npm test 39 | if (!fs.existsSync(expectedFilePath) || process.env.UPDATE_SNAPSHOT) { 40 | fs.writeFileSync(expectedFilePath, stringify(results, fixtureDir)); 41 | this.skip(); // skip when updating snapshots 42 | return; 43 | } 44 | // compare input and output 45 | const expectedContent = JSON.parse(fs.readFileSync(expectedFilePath, "utf-8")); 46 | assert.deepStrictEqual(trimUndefinedProperty(results, fixtureDir), expectedContent); 47 | }); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/another-attribute/input.adoc: -------------------------------------------------------------------------------- 1 | [doctest-state="disabled"] 2 | [source,javascript] 3 | ---- 4 | const str = "string"; 5 | console.log(str); 6 | ---- 7 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/another-attribute/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "const str = \"string\";\nconsole.log(str);", 4 | "state": "disabled", 5 | "location": { 6 | "start": { 7 | "line": 4, 8 | "column": 0 9 | }, 10 | "end": { 11 | "line": 5, 12 | "column": 17 13 | } 14 | }, 15 | "doctestOptions": { 16 | "filePath": "input.adoc" 17 | } 18 | } 19 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/disabled/input.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript,doctest-state="disabled"] 2 | ---- 3 | const str = "string"; 4 | console.log(str); 5 | ---- 6 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/disabled/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "const str = \"string\";\nconsole.log(str);", 4 | "state": "disabled", 5 | "location": { 6 | "start": { 7 | "line": 3, 8 | "column": 0 9 | }, 10 | "end": { 11 | "line": 4, 12 | "column": 17 13 | } 14 | }, 15 | "doctestOptions": { 16 | "filePath": "input.adoc" 17 | } 18 | } 19 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/enabled/input.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript,doctest-state="enabled"] 2 | ---- 3 | const str = "string"; 4 | console.log(str); 5 | ---- 6 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/enabled/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "const str = \"string\";\nconsole.log(str);", 4 | "state": "enabled", 5 | "location": { 6 | "start": { 7 | "line": 3, 8 | "column": 0 9 | }, 10 | "end": { 11 | "line": 4, 12 | "column": 17 13 | } 14 | }, 15 | "doctestOptions": { 16 | "filePath": "input.adoc" 17 | } 18 | } 19 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/error/input.adoc: -------------------------------------------------------------------------------- 1 | [doctest-error="SyntaxError"] 2 | [source,javascript] 3 | ---- 4 | +++++++ 5 | ---- 6 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/error/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "+++++++", 4 | "state": "none", 5 | "expectedError": "SyntaxError", 6 | "location": { 7 | "start": { 8 | "line": 4, 9 | "column": 0 10 | }, 11 | "end": { 12 | "line": 4, 13 | "column": 7 14 | } 15 | }, 16 | "doctestOptions": { 17 | "filePath": "input.adoc" 18 | } 19 | } 20 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/js/input.adoc: -------------------------------------------------------------------------------- 1 | [source,js] 2 | ---- 3 | const str = "string"; 4 | console.log(str); 5 | ---- 6 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/js/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "const str = \"string\";\nconsole.log(str);", 4 | "state": "none", 5 | "location": { 6 | "start": { 7 | "line": 3, 8 | "column": 0 9 | }, 10 | "end": { 11 | "line": 4, 12 | "column": 17 13 | } 14 | }, 15 | "doctestOptions": { 16 | "filePath": "input.adoc" 17 | } 18 | } 19 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/meta/input.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript,doctest-meta={ "ECMAScript": 2017 }] 2 | ---- 3 | const str = "string"; 4 | console.log(str); // => "string" 5 | ---- 6 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/meta/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "const str = \"string\";\nconsole.log(str); // => \"string\"", 4 | "state": "none", 5 | "location": { 6 | "start": { 7 | "line": 3, 8 | "column": 0 9 | }, 10 | "end": { 11 | "line": 4, 12 | "column": 32 13 | } 14 | }, 15 | "metadata": { 16 | "ECMAScript": 2017 17 | }, 18 | "doctestOptions": { 19 | "filePath": "input.adoc" 20 | } 21 | } 22 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/options/input.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript,doctest-options={ "runMode": "any" }] 2 | ---- 3 | const str = "string"; 4 | console.log(str); 5 | ---- 6 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/options/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "const str = \"string\";\nconsole.log(str);", 4 | "state": "none", 5 | "location": { 6 | "start": { 7 | "line": 3, 8 | "column": 0 9 | }, 10 | "end": { 11 | "line": 4, 12 | "column": 17 13 | } 14 | }, 15 | "doctestOptions": { 16 | "filePath": "input.adoc", 17 | "runMode": "any" 18 | } 19 | } 20 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/simple/input.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | const str = "string"; 4 | console.log(str); 5 | ---- 6 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/simple/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "const str = \"string\";\nconsole.log(str);", 4 | "state": "none", 5 | "location": { 6 | "start": { 7 | "line": 3, 8 | "column": 0 9 | }, 10 | "end": { 11 | "line": 4, 12 | "column": 17 13 | } 14 | }, 15 | "doctestOptions": { 16 | "filePath": "input.adoc" 17 | } 18 | } 19 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/source-include/input.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | include::source.js[] 4 | ---- 5 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/source-include/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "console.log(\"from source.js\");\n", 4 | "state": "none", 5 | "location": { 6 | "start": { 7 | "line": 0, 8 | "column": null 9 | }, 10 | "end": { 11 | "line": 3, 12 | "column": 2 13 | } 14 | }, 15 | "doctestOptions": { 16 | "filePath": "input.adoc" 17 | } 18 | } 19 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/source-include/source.js: -------------------------------------------------------------------------------- 1 | console.log("from source.js"); 2 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/with-another-attr/input.adoc: -------------------------------------------------------------------------------- 1 | Async Functionとは非同期処理を行う関数を定義する構文です。 2 | Async Functionは通常の関数とは異なり、必ず``Promise``インスタンスを返す関数を定義する構文です。 3 | 4 | Async Functionは次のように関数の前に``async``をつけることで定義できます。 5 | この``doAsync``関数は常に``Promise``インスタンスを返します。 6 | 7 | [role="executable"] 8 | [source,javascript] 9 | ---- 10 | async function doAsync() { 11 | return "値"; 12 | } 13 | // doAsync関数はPromiseを返す 14 | doAsync().then(function(value){ 15 | console.log(value); // => "値" 16 | }); 17 | ---- 18 | 19 | Async Functionでは``return``した値の代わりに、``Promise.resolve(返り値)``のように返り値をラップした``Promise``インスタンスを返します。 20 | そのため、このAsync Functionは次のように書いた場合と同じ意味になります。 21 | 22 | [role="executable"] 23 | [source,javascript] 24 | ---- 25 | // 通常の関数でPromiseインスタンスを返している 26 | function doAsync() { 27 | return Promise.resolve("値"); 28 | } 29 | doAsync().then(function(value){ 30 | console.log(value); // => "値" 31 | }); 32 | ---- 33 | 34 | またAsync Function内では``await``式というPromiseの非同期処理が完了するまで待つ構文が利用できます。 35 | ``await``式を使うことで非同期処理を同期処理のように扱えるため、Promiseチェーンで実現していた処理の流れを読みやすくかけます。 36 | 37 | まずは、Async Functionと``await``式を使った場合はどのように書けるかを簡単に見ていきます。 38 | 39 | 次の例では https://developer.mozilla.org/ja/docs/Web/API/Fetch_API[Fetch API] で``/json/book.json``を取得して、``title``を取り出す``getBookTitle``関数の実行結果をコンソールに出力しています。 40 | Fetch APIはURLのリソースを取得し、Promiseを返す関数です。 41 | 42 | この時、取得できる``/json/book.json``は次のような内容になっています。 43 | 44 | [[book.json]] 45 | ./json/book.json 46 | [source,json] 47 | ---- 48 | include::../json/book.json[] 49 | ---- 50 | 51 | まずは、Promise APIを使って``fetchBookTitle``関数で取得したタイトルをコンソールに出力してみます。 52 | 53 | [role="executable"] 54 | [source,javascript] 55 | ---- 56 | function fetchBookTitle(){ 57 | // Fetch APIは指定URLのリソースを取得しPromiseを返す関数 58 | return fetch("https://azu.github.io/promises-book/json/book.json").then(function(res){ 59 | return res.json(); // レスポンスをJSON形式としてパースする 60 | }).then(function(json){ 61 | return json.title; // JSONからtitleプロパティを取り出す 62 | }); 63 | } 64 | 65 | function main(){ 66 | fetchBookTitle().then(function(title){ 67 | console.log(title); // => "JavaScript Promiseの本" 68 | }); 69 | } 70 | 71 | main(); 72 | ---- 73 | 74 | 次は同様の処理をAsync Functionと``await``式で書いています。 75 | Promise APIを使っていた場合に比べて、コールバック関数がなくなっていることが分かります。 76 | 77 | [role="executable"] 78 | [source,javascript] 79 | ---- 80 | // `async`をつけて`fetchBookTitle`関数をAsync Functionとして定義 81 | async function fetchBookTitle(){ 82 | // リクエストしてリソースを取得する 83 | const res = await fetch("https://azu.github.io/promises-book/json/book.json"); 84 | // レスポンスをJSON形式としてパースする 85 | const json = await res.json(); 86 | // JSONからtitleプロパティを取り出す 87 | return json.title; 88 | } 89 | 90 | // `async`をつけて`main`関数をAsync Functionとして定義 91 | async function main(){ 92 | // `await`式で`fetchBookTitle`の非同期処理が完了するまで待つ 93 | // `fetchBookTitle`がresolveした値が返り値になる 94 | const title = await fetchBookTitle(); 95 | console.log(title); // => "JavaScript Promiseの本" 96 | } 97 | 98 | main(); 99 | ---- 100 | 101 | Async FunctionではPromiseの状態が変化するまで待つ``await``式という機能を利用できます。 102 | Promiseでは結果を``then``メソッドのコールバック関数で取得していたのが、``await``式の右辺にあるPromiseのresolveされた値が左辺の変数へと代入されます。そのため、Async Functionと``await``式を使うことで非同期処理をまるで同期処理のように書けます。 103 | 104 | この章では、このAsync Functionと``await``式について詳しく見ていきます。 105 | 106 | 重要なこととしてAsync FunctionはPromiseの上に作られた構文です。 107 | そのためAsync Functionを理解するには、Promiseを理解する必要があることに注意してください。 108 | -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/snapshots/with-another-attr/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "async function doAsync() {\n return \"値\";\n}\n// doAsync関数はPromiseを返す\ndoAsync().then(function(value){\n console.log(value); // => \"値\"\n});", 4 | "state": "none", 5 | "location": { 6 | "start": { 7 | "line": 10, 8 | "column": 0 9 | }, 10 | "end": { 11 | "line": 16, 12 | "column": 3 13 | } 14 | }, 15 | "doctestOptions": { 16 | "filePath": "input.adoc" 17 | } 18 | }, 19 | { 20 | "code": "// 通常の関数でPromiseインスタンスを返している\nfunction doAsync() {\n return Promise.resolve(\"値\");\n}\ndoAsync().then(function(value){\n console.log(value); // => \"値\"\n});", 21 | "state": "none", 22 | "location": { 23 | "start": { 24 | "line": 25, 25 | "column": 0 26 | }, 27 | "end": { 28 | "line": 31, 29 | "column": 3 30 | } 31 | }, 32 | "doctestOptions": { 33 | "filePath": "input.adoc" 34 | } 35 | }, 36 | { 37 | "code": "function fetchBookTitle(){\n // Fetch APIは指定URLのリソースを取得しPromiseを返す関数\n return fetch(\"https://azu.github.io/promises-book/json/book.json\").then(function(res){\n return res.json(); // レスポンスをJSON形式としてパースする\n }).then(function(json){\n return json.title; // JSONからtitleプロパティを取り出す\n });\n}\n\nfunction main(){\n fetchBookTitle().then(function(title){\n console.log(title); // => \"JavaScript Promiseの本\"\n });\n}\n\nmain();", 38 | "state": "none", 39 | "location": { 40 | "start": { 41 | "line": 56, 42 | "column": 0 43 | }, 44 | "end": { 45 | "line": 71, 46 | "column": 7 47 | } 48 | }, 49 | "doctestOptions": { 50 | "filePath": "input.adoc" 51 | } 52 | }, 53 | { 54 | "code": "// `async`をつけて`fetchBookTitle`関数をAsync Functionとして定義\nasync function fetchBookTitle(){\n // リクエストしてリソースを取得する\n const res = await fetch(\"https://azu.github.io/promises-book/json/book.json\");\n // レスポンスをJSON形式としてパースする\n const json = await res.json();\n // JSONからtitleプロパティを取り出す\n return json.title;\n}\n\n// `async`をつけて`main`関数をAsync Functionとして定義\nasync function main(){\n // `await`式で`fetchBookTitle`の非同期処理が完了するまで待つ\n // `fetchBookTitle`がresolveした値が返り値になる\n const title = await fetchBookTitle();\n console.log(title); // => \"JavaScript Promiseの本\"\n}\n\nmain();", 55 | "state": "none", 56 | "location": { 57 | "start": { 58 | "line": 80, 59 | "column": 0 60 | }, 61 | "end": { 62 | "line": 98, 63 | "column": 7 64 | } 65 | }, 66 | "doctestOptions": { 67 | "filePath": "input.adoc" 68 | } 69 | } 70 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "noEmit": true 6 | }, 7 | "include": [ 8 | "../src/**/*", 9 | "./**/*" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/@power-doctest/asciidoctor/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "esModuleInterop": true, 7 | "newLine": "LF", 8 | "outDir": "./lib/", 9 | "target": "es5", 10 | "sourceMap": true, 11 | "declaration": true, 12 | "jsx": "preserve", 13 | "lib": [ 14 | "esnext", 15 | "dom" 16 | ], 17 | /* Strict Type-Checking Options */ 18 | "strict": true, 19 | /* Additional Checks */ 20 | /* Report errors on unused locals. */ 21 | "noUnusedLocals": true, 22 | /* Report errors on unused parameters. */ 23 | "noUnusedParameters": true, 24 | /* Report error when not all code paths in function return a value. */ 25 | "noImplicitReturns": true, 26 | /* Report errors for fallthrough cases in switch statement. */ 27 | "noFallthroughCasesInSwitch": true 28 | }, 29 | "include": [ 30 | "src/**/*" 31 | ], 32 | "exclude": [ 33 | ".git", 34 | "node_modules" 35 | ] 36 | } -------------------------------------------------------------------------------- /packages/@power-doctest/core/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | *.swo 4 | *.swn 5 | *.swm 6 | .tern-port 7 | node_modules 8 | tags 9 | .idea/ 10 | 11 | lib -------------------------------------------------------------------------------- /packages/@power-doctest/core/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": [ 3 | "ts-node-test-register" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [5.3.3](https://github.com/azu/power-doctest/compare/v5.3.2...v5.3.3) (2023-07-15) 7 | 8 | **Note:** Version bump only for package @power-doctest/core 9 | 10 | 11 | 12 | 13 | 14 | ## [5.3.2](https://github.com/azu/power-doctest/compare/v5.3.1...v5.3.2) (2022-05-05) 15 | 16 | ### Bug Fixes 17 | 18 | * ignore parse error on espower ([#30](https://github.com/azu/power-doctest/issues/30)) ([a9b9cbe](https://github.com/azu/power-doctest/commit/a9b9cbee91174161dea1b514fde1d1d97d1f8e2e)) 19 | 20 | ## [5.3.1](https://github.com/azu/power-doctest/compare/v5.3.0...v5.3.1) (2022-01-05) 21 | 22 | ### Bug Fixes 23 | 24 | * **deps:** Update babel dependencies to ^7.16.7 ([#28](https://github.com/azu/power-doctest/issues/28)) ([92d68cd](https://github.com/azu/power-doctest/commit/92d68cd8100839cf37c409480a3a932290ff2fbe)) 25 | 26 | # [5.3.0](https://github.com/azu/power-doctest/compare/v5.2.2...v5.3.0) (2021-05-07) 27 | 28 | ### Features 29 | 30 | * **deps:** support numeric separator ([#26](https://github.com/azu/power-doctest/issues/26)) ([f0ef57b](https://github.com/azu/power-doctest/commit/f0ef57b02e767576dde6a81582025a9f19db1143)) 31 | 32 | ## [5.2.2](https://github.com/azu/power-doctest/compare/v5.2.1...v5.2.2) (2020-06-20) 33 | 34 | **Note:** Version bump only for package @power-doctest/core 35 | 36 | # [5.2.0](https://github.com/azu/power-doctest/compare/v5.1.3...v5.2.0) (2020-06-20) 37 | 38 | ### Features 39 | 40 | * **power-doctest:** support ES2020 ([ef624cb](https://github.com/azu/power-doctest/commit/ef624cb9312d62a69b72dcbbbff589557f9b93e5)) 41 | 42 | ## [5.1.2](https://github.com/azu/power-doctest/compare/v5.1.1...v5.1.2) (2019-09-01) 43 | 44 | ### Bug Fixes 45 | 46 | * **core:** use module instead of file path ([bf65ac3](https://github.com/azu/power-doctest/commit/bf65ac3)) 47 | 48 | ## [5.0.1](https://github.com/azu/power-doctest/compare/v5.0.0...v5.0.1) (2019-09-01) 49 | 50 | **Note:** Version bump only for package @power-doctest/core 51 | 52 | # [5.0.0](https://github.com/azu/power-doctest/compare/v4.1.2...v5.0.0) (2019-09-01) 53 | 54 | **Note:** Version bump only for package @power-doctest/core 55 | 56 | ## [4.1.2](https://github.com/azu/power-doctest/compare/v4.1.1...v4.1.2) (2019-09-01) 57 | 58 | **Note:** Version bump only for package @power-doctest/core 59 | 60 | # [4.0.0](https://github.com/azu/power-doctest/compare/v3.3.3...v4.0.0) (2019-09-01) 61 | 62 | **Note:** Version bump only for package power-doctest 63 | 64 | ## [3.3.2](https://github.com/azu/power-doctest/compare/v3.3.1...v3.3.2) (2019-08-25) 65 | 66 | ### Bug Fixes 67 | 68 | * **power-doctest:** disable babelrc ([d0a49b7](https://github.com/azu/power-doctest/commit/d0a49b7)) 69 | 70 | ## [3.3.1](https://github.com/azu/power-doctest/compare/v3.3.0...v3.3.1) (2019-08-25) 71 | 72 | ### Bug Fixes 73 | 74 | * **power-doctest:** disable config file ([f610d2d](https://github.com/azu/power-doctest/commit/f610d2d)) 75 | 76 | # [3.3.0](https://github.com/azu/power-doctest/compare/v3.2.1...v3.3.0) (2019-08-25) 77 | 78 | ### Features 79 | 80 | * **power-doctes:** support power-assert again ([09632ec](https://github.com/azu/power-doctest/commit/09632ec)) 81 | 82 | # 3.0.0 (2019-08-25) 83 | 84 | **Note:** Version bump only for package power-doctest 85 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 azu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/README.md: -------------------------------------------------------------------------------- 1 | # @power-doctest/core 2 | 3 | power-doctest core library. 4 | 5 | ## Features 6 | 7 | - Convert Code to power-doctest ready code. 8 | - power-doctest use [comment-to-assert](https://www.npmjs.com/package/comment-to-assert) and [power-assert](https://github.com/twada/power-assert "power-assert") 9 | 10 | 11 | ## Installation 12 | 13 | ``` sh 14 | npm install @power-doctest/core 15 | ``` 16 | 17 | ## Usage 18 | 19 | power-doctest convert following code 20 | 21 | ``` js 22 | function sum(ary) { 23 | return ary.reduce(function (current, next) { 24 | return current + next 25 | }, 0); 26 | } 27 | 28 | var total = sum([1, 2, 3, 4, 5]); 29 | total; // => 5 30 | ``` 31 | 32 | to 33 | 34 | ``` js 35 | var assert = require('power-assert'); 36 | function sum(ary) { 37 | return ary.reduce(function (current, next) { 38 | return current + next; 39 | }, 0); 40 | } 41 | var total = sum([ 42 | 1, 43 | 2, 44 | 3, 45 | 4, 46 | 5 47 | ]); 48 | assert.equal(assert._expr(assert._capt(total, 'arguments/0'), { 49 | content: 'assert.equal(total, 5)', 50 | line: 14 51 | }), 5); 52 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbXX0 53 | ``` 54 | 55 | And execute this transformed code: 56 | 57 | ```sh 58 | $ node example/transformed.js 59 | AssertionError: # at line: 14 60 | 61 | assert.equal(total, 5) 62 | | 63 | 15 64 | 65 | ``` 66 | 67 | ![assert-test](http://gyazo.com/075b4afe13003bd8691a85b371f84afe.gif) 68 | 69 | ### API 70 | 71 | - `convertCode`: Convert code to code 72 | - `convertAST`: Convert Babel's AST to AST 73 | 74 | ```ts 75 | import { ParserOptions } from "@babel/parser"; 76 | import { File } from "@babel/types"; 77 | export interface convertCodeOption { 78 | filePath: string; 79 | babel?: ParserOptions; 80 | assertBeforeCallbackName?: string; 81 | assertAfterCallbackName?: string; 82 | } 83 | /** 84 | * Convert Code to Code 85 | * @param code 86 | * @param options 87 | */ 88 | export declare function convertCode(code: string, options: convertCodeOption): string; 89 | export interface convertASTOptions { 90 | assertBeforeCallbackName?: string; 91 | assertAfterCallbackName?: string; 92 | filePath: string; 93 | } 94 | /** 95 | * Convert AST to AST 96 | * @param AST 97 | * @param options 98 | */ 99 | export declare function convertAST(AST: T, options: convertASTOptions): T; 100 | ``` 101 | 102 | ### Exception Test 103 | 104 | Look like `=> Error` is `assert.throw()`. 105 | 106 | ``` js 107 | throw new Error(); // => Error 108 | var object = {}; 109 | obj.not.found; // => Error 110 | ``` 111 | 112 | Covert this case to: 113 | 114 | ```js 115 | var assert = require('power-assert'); 116 | assert.throws(function () { 117 | throw new Error(); 118 | }, Error); 119 | var object = {}; 120 | assert.throws(function () { 121 | object.not.found; 122 | }, Error); 123 | ``` 124 | 125 | ## Contributing 126 | 127 | 1. Fork it! 128 | 2. Create your feature branch: `git checkout -b my-new-feature` 129 | 3. Commit your changes: `git commit -am 'Add some feature'` 130 | 4. Push to the branch: `git push origin my-new-feature` 131 | 5. Submit a pull request :D 132 | 133 | ## License 134 | 135 | MIT 136 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@power-doctest/core", 3 | "version": "5.3.4", 4 | "description": "power-doctest core library", 5 | "homepage": "https://github.com/azu/power-doctest", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/azu/power-doctest.git" 9 | }, 10 | "license": "MIT", 11 | "author": "azu", 12 | "files": [ 13 | "bin", 14 | "src", 15 | "lib" 16 | ], 17 | "main": "lib/power-doctest.js", 18 | "types": "lib/power-doctest.d.ts", 19 | "scripts": { 20 | "build": "tsc -p .", 21 | "prepublish": "npm run --if-present build", 22 | "test": "mocha \"test/**/*.ts\"", 23 | "updateSnapshot": "UPDATE_SNAPSHOT=1 npm test", 24 | "watch": "tsc -p . --watch" 25 | }, 26 | "dependencies": { 27 | "@babel/core": "^7.16.7", 28 | "@babel/parser": "^7.16.7", 29 | "@babel/template": "^7.16.7", 30 | "@babel/traverse": "^7.16.7", 31 | "@babel/types": "^7.16.7", 32 | "babel-plugin-espower": "^3.0.1", 33 | "comment-to-assert": "workspace:^", 34 | "espower": "^2.1.2", 35 | "power-assert": "^1.6.1" 36 | }, 37 | "devDependencies": { 38 | "@babel/generator": "^7.16.7", 39 | "@types/babel__core": "^7.1.18", 40 | "@types/babel__generator": "^7.6.4", 41 | "@types/babel__template": "^7.4.1", 42 | "@types/babel__traverse": "^7.14.2", 43 | "@types/mocha": "^10.0.1", 44 | "@types/node": "^22.13.8", 45 | "mocha": "^11.1.0", 46 | "ts-node": "^10.4.0", 47 | "ts-node-test-register": "^10.0.0", 48 | "typescript": "^5.1.6" 49 | }, 50 | "peerDependecies": {}, 51 | "tags": [ 52 | "doctest", 53 | "power-assert", 54 | "testing", 55 | "AST" 56 | ], 57 | "publishConfig": { 58 | "access": "public" 59 | }, 60 | "gitHead": "f5473fe0c929896882fb8201e23745a9116b1159" 61 | } 62 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/src/inject-assert.ts: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import traverse from "@babel/traverse"; 4 | import template from "@babel/template"; 5 | import { Node } from "@babel/types"; 6 | 7 | export function injectAssertModule(AST: Node) { 8 | traverse(AST, { 9 | Program: { 10 | enter(path) { 11 | path.unshiftContainer("body", template`var assert = require("power-assert")`()); 12 | } 13 | } 14 | }); 15 | return AST; 16 | } 17 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/src/power-doctest.ts: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import { parse, ParserOptions } from "@babel/parser"; 4 | import { File } from "@babel/types"; 5 | import { transformSync } from "@babel/core"; 6 | import generate from "@babel/generator"; 7 | import assert from "assert"; 8 | import { toAssertFromAST } from "comment-to-assert"; 9 | import { injectAssertModule } from "./inject-assert"; 10 | 11 | const babelPluginEspower = require("babel-plugin-espower"); 12 | 13 | export interface convertCodeOption { 14 | filePath: string; 15 | babel?: ParserOptions; 16 | assertBeforeCallbackName?: string; 17 | assertAfterCallbackName?: string; 18 | } 19 | 20 | /** 21 | * Convert Code to Code 22 | * @param code 23 | * @param options 24 | */ 25 | export function convertCode(code: string, options: convertCodeOption): string { 26 | const AST = parse(code, { 27 | sourceType: "module", 28 | ...(options.babel ? options.babel : {}) 29 | }); 30 | const output = convertAST(AST, { 31 | assertBeforeCallbackName: options.assertBeforeCallbackName, 32 | assertAfterCallbackName: options.assertAfterCallbackName, 33 | filePath: options.filePath 34 | }); 35 | return generate(output as any, { 36 | comments: true 37 | }).code; 38 | } 39 | 40 | export interface convertASTOptions { 41 | assertBeforeCallbackName?: string; 42 | assertAfterCallbackName?: string; 43 | // pseudo file path 44 | filePath: string; 45 | } 46 | 47 | /** 48 | * Convert AST to AST 49 | * @param AST 50 | * @param options 51 | */ 52 | export function convertAST(AST: T, options: convertASTOptions): T { 53 | const boundEspower = (AST: T) => { 54 | const { code } = generate(AST, { 55 | comments: true 56 | }); 57 | try { 58 | const result = transformSync(code, { 59 | plugins: [babelPluginEspower], 60 | filename: options.filePath, 61 | sourceFileName: options.filePath, 62 | ast: true, 63 | code: true, 64 | configFile: false, 65 | babelrc: false, 66 | sourceType: "module" 67 | }); 68 | if (!result) { 69 | throw new Error("Fail to convert espower in power-doctest"); 70 | } 71 | return result.ast; 72 | } catch (error) { 73 | // TODO: workaround https://github.com/azu/power-doctest/issues/29 74 | if (process.env.DEBUG) { 75 | console.error("espower error", error); 76 | console.log(code); 77 | console.log(AST); 78 | } 79 | return AST; 80 | } 81 | }; 82 | const commentToAssert = (AST: T) => { 83 | return toAssertFromAST(AST, options); 84 | }; 85 | const modifyMapFunctionList: ((ast: any) => any)[] = [commentToAssert, injectAssertModule, boundEspower]; 86 | return modifyMapFunctionList.reduce((AST, modify, index) => { 87 | const result = modify(AST); 88 | assert(result != null, modifyMapFunctionList[index].name + " return wrong result. result: " + result); 89 | return result; 90 | }, AST); 91 | } 92 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/power-doctest.test.ts: -------------------------------------------------------------------------------- 1 | import assert from "assert"; 2 | import { convertAST, convertASTOptions, convertCode } from "../src/power-doctest"; 3 | import { parse } from "@babel/parser"; 4 | import generate from "@babel/generator"; 5 | 6 | function parseAndConvert(code: string, options?: convertASTOptions): any { 7 | const AST = parse(code, { 8 | sourceType: "module" 9 | }); 10 | return convertAST(AST, { 11 | filePath: "test.js", 12 | ...options 13 | }); 14 | } 15 | 16 | const astEqual = (a: any, b: any) => { 17 | let ast = parse(b, { 18 | sourceType: "module" 19 | }); 20 | assert.strictEqual(generate(a).code, generate(ast as any).code); 21 | }; 22 | 23 | describe("core", function () { 24 | describe("#convertCode", function () { 25 | it("should convert code to code", function () { 26 | var code = `function addPrefix(text, prefix = "デフォルト:") { 27 | return prefix + text; 28 | }`; 29 | var result = convertCode(code, { 30 | filePath: "test.js" 31 | }); 32 | assert.strictEqual( 33 | result, 34 | `var assert = require("power-assert"); 35 | function addPrefix(text, prefix = "デフォルト:") { 36 | return prefix + text; 37 | }`.trim() 38 | ); 39 | }); 40 | }); 41 | describe("#convertAST", function () { 42 | it("add assert module to header", function () { 43 | var code = "var a = 1;"; 44 | var resultAST = parseAndConvert(code); 45 | astEqual( 46 | resultAST, 47 | ` 48 | var assert = require("power-assert"); 49 | var a = 1; 50 | ` 51 | ); 52 | }); 53 | it("add assert module to ", function () { 54 | var code = "var a = 1;"; 55 | var resultAST = parseAndConvert(code); 56 | astEqual( 57 | resultAST, 58 | ` 59 | var assert = require("power-assert"); 60 | var a = 1; 61 | ` 62 | ); 63 | }); 64 | it("module type", function () { 65 | var code = ` 66 | export default function hello() { 67 | var a = 1; 68 | } 69 | `; 70 | var resultAST = parseAndConvert(code); 71 | astEqual( 72 | resultAST, 73 | ` 74 | var assert = require("power-assert"); 75 | export default function hello() { 76 | var a = 1; 77 | } 78 | ` 79 | ); 80 | }); 81 | 82 | it("should support async function", function () { 83 | var code = ` 84 | async function hello() { 85 | var a = 1; 86 | console.log(a); // => 1 87 | } 88 | hello(); 89 | `; 90 | const resultAST = parseAndConvert(code); 91 | const resultCode = generate(resultAST).code; 92 | assert.ok(resultCode.includes("assert.strictEqual")); 93 | }); 94 | it("convert assert to power-assert format, it contain assert function", function () { 95 | var code = ` 96 | var a = 1; 97 | a; // => 1`; 98 | var resultAST = parseAndConvert(code); 99 | const resultCode = generate(resultAST).code; 100 | assert.ok(resultCode.includes("assert.strictEqual")); 101 | }); 102 | it("should support callback function", function () { 103 | var code = ` 104 | var a = 1; 105 | console.log(a); // => 1 106 | `; 107 | const resultAST = parseAndConvert(code, { 108 | filePath: "test.js", 109 | assertBeforeCallbackName: "before", 110 | assertAfterCallbackName: "after" 111 | }); 112 | const resultCode = generate(resultAST).code; 113 | assert.ok(resultCode.includes("before(")); 114 | assert.ok(resultCode.includes("after(")); 115 | }); 116 | }); 117 | }); 118 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/snapshot.test.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import * as path from "path"; 3 | import * as assert from "assert"; 4 | // transform function 5 | import { convertCode } from "../src/power-doctest"; 6 | 7 | const fixturesDir = path.join(__dirname, "snapshots"); 8 | describe("Snapshot testing", () => { 9 | fs.readdirSync(fixturesDir).map((caseName) => { 10 | const normalizedTestName = caseName.replace(/-/g, " "); 11 | it(`Test ${normalizedTestName}`, async function () { 12 | const fixtureDir = path.join(fixturesDir, caseName); 13 | const actualFilePath = path.join(fixtureDir, "input.js"); 14 | const actualContent = fs.readFileSync(actualFilePath, "utf-8"); 15 | const actualOptionFilePath = path.join(fixtureDir, "options.json"); 16 | const actualOptions = { 17 | ...{ 18 | filePath: actualFilePath 19 | }, 20 | ...(fs.existsSync(actualOptionFilePath) 21 | ? { 22 | ...JSON.parse(fs.readFileSync(actualOptionFilePath, "utf-8")) 23 | } 24 | : {}) 25 | }; 26 | const actual = convertCode(actualContent, actualOptions); 27 | const expectedFilePath = path.join(fixtureDir, "output.js"); 28 | // Usage: update snapshots 29 | // UPDATE_SNAPSHOT=1 npm test 30 | if (!fs.existsSync(expectedFilePath) || process.env.UPDATE_SNAPSHOT) { 31 | fs.writeFileSync(expectedFilePath, actual); 32 | this.skip(); // skip when updating snapshots 33 | return; 34 | } 35 | // compare input and output 36 | const expectedContent = fs.readFileSync(expectedFilePath, "utf-8"); 37 | assert.deepStrictEqual( 38 | actual, 39 | expectedContent, 40 | ` 41 | ${fixtureDir} 42 | ${actual} 43 | ` 44 | ); 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/snapshots/async-function/input.js: -------------------------------------------------------------------------------- 1 | async function doAsync() { 2 | return "値"; 3 | } 4 | // doAsync関数はPromiseを返す 5 | doAsync().then(value => { 6 | console.log(value); // => "値" 7 | }); 8 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/snapshots/bigint/input.js: -------------------------------------------------------------------------------- 1 | 1n; // => 1n 2 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/snapshots/console/input.js: -------------------------------------------------------------------------------- 1 | console.log(1); // => 1 2 | console.log("str"); // => "str" 3 | console.log(true); // => true 4 | console.log([1, 2, 3]); //=> [1,2,3] 5 | const object = { a: 1 }; 6 | console.log(object); // => { a: 1 } 7 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/snapshots/end-semicolon/input.js: -------------------------------------------------------------------------------- 1 | function* naturals() { 2 | let i = 0; 3 | while (true) { 4 | yield i; 5 | i += 1; 6 | } 7 | } 8 | 9 | const result = naturals() 10 | .map(value => { 11 | return value * value; 12 | }); 13 | result.next(); // => {value: 0, done: false}; 14 | result.next(); // => {value:31, done: false}; 15 | result.next(); // => {value: 4, done: false}; 16 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/snapshots/error/input.js: -------------------------------------------------------------------------------- 1 | throw new Error("message"); // => Error: "message" 2 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/snapshots/error/output.js: -------------------------------------------------------------------------------- 1 | var assert = require("power-assert"); 2 | assert.throws(function () { 3 | throw new Error("message"); 4 | }); // => Error: "message" -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/snapshots/es2022-top-level-await/input.js: -------------------------------------------------------------------------------- 1 | console.log(await 1); // => 1 2 | console.log(await new Promise(resolve => resolve(2))); // => 2 3 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/snapshots/literal/input.js: -------------------------------------------------------------------------------- 1 | 1; // => 1 2 | ("str"); // => "str" 3 | [1, 2, 3]; //=> [1,2,3] 4 | const object = { a: 1 }; 5 | object; // => { a: 1 } 6 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/snapshots/object/input.js: -------------------------------------------------------------------------------- 1 | const objectA = { 2 | a: { 3 | b: { 4 | c: 333 5 | } 6 | } 7 | }; 8 | const objectB = { 9 | a: { 10 | b: { 11 | c: 333 12 | } 13 | } 14 | }; 15 | console.log(objectA); // => objectB 16 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/snapshots/private-fields/input.js: -------------------------------------------------------------------------------- 1 | class PrivateExampleClass { 2 | #privateField = 42; 3 | dump() { 4 | console.log(this.#privateField); // => 42 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/snapshots/private-fields/output.js: -------------------------------------------------------------------------------- 1 | var assert = require("power-assert"); 2 | class PrivateExampleClass { 3 | #privateField = 42; 4 | dump() { 5 | assert.strictEqual(this.#privateField, 42); // => 42 6 | } 7 | } -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/snapshots/promise/input.js: -------------------------------------------------------------------------------- 1 | Promise.resolve(1); // => Resolve: 1 2 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/snapshots/timeout/input.js: -------------------------------------------------------------------------------- 1 | setTimeout(() => { 2 | console.log("???"); // => "???" 3 | }, 100); 4 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "noEmit": true, 6 | "allowJs": true 7 | }, 8 | "include": [ 9 | "../src/**/*", 10 | "./**/*" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /packages/@power-doctest/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "esModuleInterop": true, 7 | "newLine": "LF", 8 | "outDir": "./lib/", 9 | "target": "es5", 10 | "sourceMap": true, 11 | "declaration": true, 12 | "jsx": "preserve", 13 | "lib": [ 14 | "esnext", 15 | "dom" 16 | ], 17 | /* Strict Type-Checking Options */ 18 | "strict": true, 19 | /* Additional Checks */ 20 | /* Report errors on unused locals. */ 21 | "noUnusedLocals": true, 22 | /* Report errors on unused parameters. */ 23 | "noUnusedParameters": true, 24 | /* Report error when not all code paths in function return a value. */ 25 | "noImplicitReturns": true, 26 | /* Report errors for fallthrough cases in switch statement. */ 27 | "noFallthroughCasesInSwitch": true 28 | }, 29 | "include": [ 30 | "src/**/*" 31 | ], 32 | "exclude": [ 33 | ".git", 34 | "node_modules" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": [ 3 | "ts-node-test-register" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [5.3.3](https://github.com/azu/power-doctest/compare/v5.3.2...v5.3.3) (2023-07-15) 7 | 8 | **Note:** Version bump only for package @power-doctest/javascript 9 | 10 | 11 | 12 | 13 | 14 | ## [5.3.1](https://github.com/azu/power-doctest/compare/v5.3.0...v5.3.1) (2022-01-05) 15 | 16 | 17 | ### Bug Fixes 18 | 19 | * **deps:** Update babel dependencies to ^7.16.7 ([#28](https://github.com/azu/power-doctest/issues/28)) ([92d68cd](https://github.com/azu/power-doctest/commit/92d68cd8100839cf37c409480a3a932290ff2fbe)) 20 | 21 | 22 | 23 | 24 | 25 | # [5.3.0](https://github.com/azu/power-doctest/compare/v5.2.2...v5.3.0) (2021-05-07) 26 | 27 | 28 | ### Features 29 | 30 | * **deps:** support numeric separator ([#26](https://github.com/azu/power-doctest/issues/26)) ([f0ef57b](https://github.com/azu/power-doctest/commit/f0ef57b02e767576dde6a81582025a9f19db1143)) 31 | 32 | 33 | 34 | 35 | 36 | # [5.2.0](https://github.com/azu/power-doctest/compare/v5.1.3...v5.2.0) (2020-06-20) 37 | 38 | 39 | ### Features 40 | 41 | * **power-doctest:** support ES2020 ([ef624cb](https://github.com/azu/power-doctest/commit/ef624cb9312d62a69b72dcbbbff589557f9b93e5)) 42 | 43 | 44 | 45 | 46 | 47 | ## [5.0.1](https://github.com/azu/power-doctest/compare/v5.0.0...v5.0.1) (2019-09-01) 48 | 49 | **Note:** Version bump only for package @power-doctest/javascript 50 | 51 | 52 | 53 | 54 | 55 | # [5.0.0](https://github.com/azu/power-doctest/compare/v4.1.2...v5.0.0) (2019-09-01) 56 | 57 | **Note:** Version bump only for package @power-doctest/javascript 58 | 59 | 60 | 61 | 62 | 63 | ## [4.1.2](https://github.com/azu/power-doctest/compare/v4.1.1...v4.1.2) (2019-09-01) 64 | 65 | **Note:** Version bump only for package @power-doctest/javascript 66 | 67 | 68 | 69 | 70 | 71 | # [4.0.0](https://github.com/azu/power-doctest/compare/v3.3.3...v4.0.0) (2019-09-01) 72 | 73 | 74 | ### Bug Fixes 75 | 76 | * **power-doctest:** add try-catch ([5e5e8da](https://github.com/azu/power-doctest/commit/5e5e8da)) 77 | * fix tester requireMock ([a4e0574](https://github.com/azu/power-doctest/commit/a4e0574)) 78 | 79 | 80 | ### Features 81 | 82 | * **@power-doctest/javascript:** add package ([79927f5](https://github.com/azu/power-doctest/commit/79927f5)) 83 | * **cli:** add CLI ([4bb1f7a](https://github.com/azu/power-doctest/commit/4bb1f7a)) 84 | -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 azu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/README.md: -------------------------------------------------------------------------------- 1 | # @power-doctest/javascript 2 | 3 | A JavaScript parser for power-doctest. 4 | 5 | ## Install 6 | 7 | Install with [npm](https://www.npmjs.com/): 8 | 9 | npm install @power-doctest/javascript 10 | 11 | ## Usage 12 | 13 | ### Doctest Control Annotation 14 | 15 | Write Doctest Control Annotation as comment 16 | 17 | #### Enable doctest 18 | 19 | Enable doctest for the source code. 20 | 21 | ```js 22 | // doctest-enabled 23 | ``` 24 | 25 | #### Disable doctest 26 | 27 | Disable doctest for the source code. 28 | 29 | ```js 30 | // doctest-disbaled 31 | ``` 32 | 33 | ### Expected Error 34 | 35 | If the expected error is not match the result, throw error. 36 | 37 | ```js 38 | // doctest-error: SyntaxError 39 | 40 | ++SHOULD BE SyntaxError++ 41 | ``` 42 | 43 | #### Options 44 | 45 | Pass `options` to [@power-doctest/tester](https://www.npmjs.com/package/@power-doctest/tester) 46 | The inline options is preferred constructor options. 47 | ```js 48 | // doctest-options:{ "runMode": "any" } 49 | ``` 50 | 51 | #### Metadata 52 | 53 | Write metadata to doctest. 54 | 55 | ```js 56 | // doctest-meta:{ "key": "value" } 57 | ``` 58 | 59 | ## Changelog 60 | 61 | See [Releases page](https://github.com/azu/power-doctest/releases). 62 | 63 | ## Running tests 64 | 65 | Install devDependencies and Run `npm test`: 66 | 67 | npm test 68 | 69 | ## Contributing 70 | 71 | Pull requests and stars are always welcome. 72 | 73 | For bugs and feature requests, [please create an issue](https://github.com/azu/power-doctest/issues). 74 | 75 | 1. Fork it! 76 | 2. Create your feature branch: `git checkout -b my-new-feature` 77 | 3. Commit your changes: `git commit -am 'Add some feature'` 78 | 4. Push to the branch: `git push origin my-new-feature` 79 | 5. Submit a pull request :D 80 | 81 | ## Author 82 | 83 | - [github/azu](https://github.com/azu) 84 | - [twitter/azu_re](https://twitter.com/azu_re) 85 | 86 | ## License 87 | 88 | MIT © azu 89 | -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@power-doctest/javascript", 3 | "version": "5.3.4", 4 | "description": "A JavaScript parser for power-doctest.", 5 | "keywords": [ 6 | "parser", 7 | "power-doctest" 8 | ], 9 | "homepage": "https://github.com/azu/power-doctest/tree/master/packages/@power-doctest/javascript/", 10 | "bugs": { 11 | "url": "https://github.com/azu/power-doctest/issues" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/azu/power-doctest.git" 16 | }, 17 | "license": "MIT", 18 | "author": "azu", 19 | "files": [ 20 | "bin/", 21 | "lib/", 22 | "src/" 23 | ], 24 | "main": "lib/index.js", 25 | "types": "lib/index.d.ts", 26 | "directories": { 27 | "lib": "lib", 28 | "test": "test" 29 | }, 30 | "scripts": { 31 | "build": "tsc -p .", 32 | "updateSnapshot": "UPDATE_SNAPSHOT=1 npm test", 33 | "clean": "rimraf lib/", 34 | "prettier": "prettier --write \"**/*.{js,jsx,ts,tsx,css}\"", 35 | "prepublish": "npm run --if-present build", 36 | "test": "mocha \"test/**/*.ts\"", 37 | "watch": "tsc -p . --watch" 38 | }, 39 | "prettier": { 40 | "printWidth": 120, 41 | "singleQuote": false, 42 | "tabWidth": 4 43 | }, 44 | "dependencies": { 45 | "@power-doctest/types": "workspace:^", 46 | "structured-source": "^4.0.0" 47 | }, 48 | "devDependencies": { 49 | "@types/mocha": "^10.0.1", 50 | "@types/node": "^22.13.8", 51 | "mocha": "^11.1.0", 52 | "prettier": "^3.0.0", 53 | "rimraf": "^6.0.1", 54 | "ts-node": "^10.4.0", 55 | "ts-node-test-register": "^10.0.0", 56 | "typescript": "^5.1.6" 57 | }, 58 | "publishConfig": { 59 | "access": "public" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/src/index.ts: -------------------------------------------------------------------------------- 1 | import { ParsedResults, ParserArgs } from "@power-doctest/types"; 2 | import { StructuredSource } from "structured-source"; 3 | 4 | const getState = (code: string): "enabled" | "disabled" | "none" => { 5 | if (/\/\/\s*doctest-disable(d)?/.test(code)) { 6 | return "disabled"; 7 | } else if (/\/\/\s*doctest-enable(d)?/.test(code)) { 8 | return "enabled"; 9 | } 10 | return "none"; 11 | }; 12 | 13 | const getExpectedError = (code: string): string | undefined => { 14 | const pattern = /\/\/\s*doctest-error:\s*(\w+Error)/; 15 | const match = code.match(pattern); 16 | if (match && match[1]) { 17 | return match[1]; 18 | } 19 | return; 20 | }; 21 | 22 | const getMeta = (code: string): {} | undefined => { 23 | const pattern = /\/\/\s*doctest-meta:{(.*)}/; 24 | const match = code.match(pattern); 25 | const metaString = match && match[1]; 26 | if (!metaString) { 27 | return; 28 | } 29 | try { 30 | return JSON.parse(metaString); 31 | } catch (error) { 32 | // parse error 33 | throw new Error(`Can not parsed. // doctest-meta:{...} should be JSON object: ${error}`); 34 | } 35 | }; 36 | 37 | const getOptions = (code: string): {} | undefined => { 38 | const pattern = /\/\/\s*doctest-options:{(.*)}/; 39 | const match = code.match(pattern); 40 | const metaString = match && match[1]; 41 | if (!metaString) { 42 | return; 43 | } 44 | try { 45 | return JSON.parse(metaString); 46 | } catch (error) { 47 | // parse error 48 | throw new Error(`Can not parsed. // doctest-options:{...} should be JSON object: ${error}`); 49 | } 50 | }; 51 | 52 | export const parse = ({ content, filePath }: ParserArgs): ParsedResults => { 53 | const source = new StructuredSource(content); 54 | const meta = getMeta(content); 55 | const options = getOptions(content); 56 | return [ 57 | { 58 | code: content, 59 | location: { 60 | start: source.indexToPosition(0), 61 | end: source.indexToPosition(content.length - 1), 62 | }, 63 | state: getState(content), 64 | expectedError: getExpectedError(content), 65 | metadata: meta, 66 | doctestOptions: options 67 | ? { 68 | filePath, 69 | ...options, 70 | } 71 | : { 72 | filePath, 73 | }, 74 | }, 75 | ]; 76 | }; 77 | -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/test/snapshot.test.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import * as path from "path"; 3 | import * as assert from "assert"; 4 | import { parse } from "../src"; 5 | 6 | const fixturesDir = path.join(__dirname, "snapshots"); 7 | 8 | const trimUndefinedProperty = (o: T, baseDir: string): T => { 9 | return JSON.parse(stringify(o as {}, baseDir)); 10 | }; 11 | const stringify = (o: {}, baseDir: string): string => { 12 | return JSON.stringify( 13 | o, 14 | (key: string, value: any) => { 15 | if (key === "filePath") { 16 | return path.relative(baseDir, value); 17 | } else { 18 | return value; 19 | } 20 | }, 21 | 4, 22 | ); 23 | }; 24 | describe("Snapshot testing", () => { 25 | fs.readdirSync(fixturesDir).map((caseName) => { 26 | const normalizedTestName = caseName.replace(/-/g, " "); 27 | it(`Test ${normalizedTestName}`, async function () { 28 | const fixtureDir = path.join(fixturesDir, caseName); 29 | const actualFilePath = path.join(fixtureDir, "input.js"); 30 | const actualContent = fs.readFileSync(actualFilePath, "utf-8"); 31 | const results = parse({ 32 | content: actualContent, 33 | filePath: actualFilePath, 34 | }); 35 | const expectedFilePath = path.join(fixtureDir, "output.json"); 36 | // Usage: update snapshots 37 | // UPDATE_SNAPSHOT=1 npm test 38 | if (!fs.existsSync(expectedFilePath) || process.env.UPDATE_SNAPSHOT) { 39 | fs.writeFileSync(expectedFilePath, stringify(results, fixtureDir)); 40 | this.skip(); // skip when updating snapshots 41 | return; 42 | } 43 | // compare input and output 44 | const expectedContent = JSON.parse(fs.readFileSync(expectedFilePath, "utf-8")); 45 | assert.deepStrictEqual(trimUndefinedProperty(results, fixtureDir), expectedContent); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/test/snapshots/disabled/input.js: -------------------------------------------------------------------------------- 1 | // doctest-disabled 2 | const array = [1, 2, 3]; 3 | console.log(array); // => [1,2,3] 4 | -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/test/snapshots/disabled/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "// doctest-disabled\nconst array = [1, 2, 3];\nconsole.log(array); // => [1,2,3]\n", 4 | "location": { 5 | "start": { 6 | "line": 1, 7 | "column": 0 8 | }, 9 | "end": { 10 | "line": 3, 11 | "column": 33 12 | } 13 | }, 14 | "state": "disabled", 15 | "doctestOptions": { 16 | "filePath": "input.js" 17 | } 18 | } 19 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/test/snapshots/enabled/input.js: -------------------------------------------------------------------------------- 1 | // doctest-enabled 2 | const array = [1, 2, 3]; 3 | console.log(array); // => [1,2,3] 4 | -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/test/snapshots/enabled/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "// doctest-enabled\nconst array = [1, 2, 3];\nconsole.log(array); // => [1,2,3]\n", 4 | "location": { 5 | "start": { 6 | "line": 1, 7 | "column": 0 8 | }, 9 | "end": { 10 | "line": 3, 11 | "column": 33 12 | } 13 | }, 14 | "state": "enabled", 15 | "doctestOptions": { 16 | "filePath": "input.js" 17 | } 18 | } 19 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/test/snapshots/expected-error/input.js: -------------------------------------------------------------------------------- 1 | // doctest-error: SyntaxError 2 | ++++++ 3 | -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/test/snapshots/expected-error/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "// doctest-error: SyntaxError\n++++++\n", 4 | "location": { 5 | "start": { 6 | "line": 1, 7 | "column": 0 8 | }, 9 | "end": { 10 | "line": 2, 11 | "column": 6 12 | } 13 | }, 14 | "state": "none", 15 | "expectedError": "SyntaxError", 16 | "doctestOptions": { 17 | "filePath": "input.js" 18 | } 19 | } 20 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/test/snapshots/ok.no-assert/error.txt: -------------------------------------------------------------------------------- 1 | NO ERROR -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/test/snapshots/ok.no-assert/input.js: -------------------------------------------------------------------------------- 1 | const value = "no assert code"; 2 | -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/test/snapshots/ok.no-assert/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "const value = \"no assert code\";\n", 4 | "location": { 5 | "start": { 6 | "line": 1, 7 | "column": 0 8 | }, 9 | "end": { 10 | "line": 1, 11 | "column": 31 12 | } 13 | }, 14 | "state": "none", 15 | "doctestOptions": { 16 | "filePath": "input.js" 17 | } 18 | } 19 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/test/snapshots/ok/input.js: -------------------------------------------------------------------------------- 1 | const array = [1, 2, 3]; 2 | console.log(array); // => [1,2,3] 3 | -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/test/snapshots/ok/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "const array = [1, 2, 3];\nconsole.log(array); // => [1,2,3]\n", 4 | "location": { 5 | "start": { 6 | "line": 1, 7 | "column": 0 8 | }, 9 | "end": { 10 | "line": 2, 11 | "column": 33 12 | } 13 | }, 14 | "state": "none", 15 | "doctestOptions": { 16 | "filePath": "input.js" 17 | } 18 | } 19 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "noEmit": true 6 | }, 7 | "include": [ 8 | "../src/**/*", 9 | "./**/*" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/@power-doctest/javascript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "esModuleInterop": true, 7 | "newLine": "LF", 8 | "outDir": "./lib/", 9 | "target": "es5", 10 | "sourceMap": true, 11 | "declaration": true, 12 | "jsx": "preserve", 13 | "lib": [ 14 | "esnext", 15 | "dom" 16 | ], 17 | /* Strict Type-Checking Options */ 18 | "strict": true, 19 | /* Additional Checks */ 20 | /* Report errors on unused locals. */ 21 | "noUnusedLocals": true, 22 | /* Report errors on unused parameters. */ 23 | "noUnusedParameters": true, 24 | /* Report error when not all code paths in function return a value. */ 25 | "noImplicitReturns": true, 26 | /* Report errors for fallthrough cases in switch statement. */ 27 | "noFallthroughCasesInSwitch": true 28 | }, 29 | "include": [ 30 | "src/**/*" 31 | ], 32 | "exclude": [ 33 | ".git", 34 | "node_modules" 35 | ] 36 | } -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore/d2c1bb2b9c72ead618c9f6a48280ebc7a8e0dff6/Node.gitignore 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | .env.test 62 | 63 | # parcel-bundler cache (https://parceljs.org/) 64 | .cache 65 | 66 | # next.js build output 67 | .next 68 | 69 | # nuxt.js build output 70 | .nuxt 71 | 72 | # vuepress build output 73 | .vuepress/dist 74 | 75 | # Serverless directories 76 | .serverless/ 77 | 78 | # FuseBox cache 79 | .fusebox/ 80 | 81 | # DynamoDB Local files 82 | .dynamodb/ 83 | 84 | 85 | ### https://raw.github.com/github/gitignore/d2c1bb2b9c72ead618c9f6a48280ebc7a8e0dff6/Global/JetBrains.gitignore 86 | 87 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 88 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 89 | 90 | # User-specific stuff 91 | .idea/**/workspace.xml 92 | .idea/**/tasks.xml 93 | .idea/**/usage.statistics.xml 94 | .idea/**/dictionaries 95 | .idea/**/shelf 96 | 97 | # Generated files 98 | .idea/**/contentModel.xml 99 | 100 | # Sensitive or high-churn files 101 | .idea/**/dataSources/ 102 | .idea/**/dataSources.ids 103 | .idea/**/dataSources.local.xml 104 | .idea/**/sqlDataSources.xml 105 | .idea/**/dynamic.xml 106 | .idea/**/uiDesigner.xml 107 | .idea/**/dbnavigator.xml 108 | 109 | # Gradle 110 | .idea/**/gradle.xml 111 | .idea/**/libraries 112 | 113 | # Gradle and Maven with auto-import 114 | # When using Gradle or Maven with auto-import, you should exclude module files, 115 | # since they will be recreated, and may cause churn. Uncomment if using 116 | # auto-import. 117 | # .idea/modules.xml 118 | # .idea/*.iml 119 | # .idea/modules 120 | 121 | # CMake 122 | cmake-build-*/ 123 | 124 | # Mongo Explorer plugin 125 | .idea/**/mongoSettings.xml 126 | 127 | # File-based project format 128 | *.iws 129 | 130 | # IntelliJ 131 | out/ 132 | 133 | # mpeltonen/sbt-idea plugin 134 | .idea_modules/ 135 | 136 | # JIRA plugin 137 | atlassian-ide-plugin.xml 138 | 139 | # Cursive Clojure plugin 140 | .idea/replstate.xml 141 | 142 | # Crashlytics plugin (for Android Studio and IntelliJ) 143 | com_crashlytics_export_strings.xml 144 | crashlytics.properties 145 | crashlytics-build.properties 146 | fabric.properties 147 | 148 | # Editor-based Rest Client 149 | .idea/httpRequests 150 | 151 | # Android studio 3.1+ serialized cache file 152 | .idea/caches/build_file_checksums.ser 153 | 154 | 155 | /lib 156 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": [ 3 | "ts-node-test-register" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [5.3.3](https://github.com/azu/power-doctest/compare/v5.3.2...v5.3.3) (2023-07-15) 7 | 8 | **Note:** Version bump only for package @power-doctest/markdown 9 | 10 | 11 | 12 | 13 | 14 | ## [5.3.2](https://github.com/azu/power-doctest/compare/v5.3.1...v5.3.2) (2022-05-05) 15 | 16 | **Note:** Version bump only for package @power-doctest/markdown 17 | 18 | ## [5.3.1](https://github.com/azu/power-doctest/compare/v5.3.0...v5.3.1) (2022-01-05) 19 | 20 | ### Bug Fixes 21 | 22 | * **deps:** Update babel dependencies to ^7.16.7 ([#28](https://github.com/azu/power-doctest/issues/28)) ([92d68cd](https://github.com/azu/power-doctest/commit/92d68cd8100839cf37c409480a3a932290ff2fbe)) 23 | 24 | # [5.3.0](https://github.com/azu/power-doctest/compare/v5.2.2...v5.3.0) (2021-05-07) 25 | 26 | ### Features 27 | 28 | * **deps:** support numeric separator ([#26](https://github.com/azu/power-doctest/issues/26)) ([f0ef57b](https://github.com/azu/power-doctest/commit/f0ef57b02e767576dde6a81582025a9f19db1143)) 29 | 30 | # [5.2.0](https://github.com/azu/power-doctest/compare/v5.1.3...v5.2.0) (2020-06-20) 31 | 32 | ### Features 33 | 34 | * **power-doctest:** support ES2020 ([ef624cb](https://github.com/azu/power-doctest/commit/ef624cb9312d62a69b72dcbbbff589557f9b93e5)) 35 | 36 | ## [5.0.1](https://github.com/azu/power-doctest/compare/v5.0.0...v5.0.1) (2019-09-01) 37 | 38 | **Note:** Version bump only for package @power-doctest/markdown 39 | 40 | # [5.0.0](https://github.com/azu/power-doctest/compare/v4.1.2...v5.0.0) (2019-09-01) 41 | 42 | **Note:** Version bump only for package @power-doctest/markdown 43 | 44 | ## [4.1.2](https://github.com/azu/power-doctest/compare/v4.1.1...v4.1.2) (2019-09-01) 45 | 46 | **Note:** Version bump only for package @power-doctest/markdown 47 | 48 | # [4.0.0](https://github.com/azu/power-doctest/compare/v3.3.3...v4.0.0) (2019-09-01) 49 | 50 | ### Features 51 | 52 | * **cli:** add CLI ([4bb1f7a](https://github.com/azu/power-doctest/commit/4bb1f7a)) 53 | 54 | ## [3.3.3](https://github.com/azu/power-doctest/compare/v3.3.2...v3.3.3) (2019-08-25) 55 | 56 | **Note:** Version bump only for package @power-doctest/markdown 57 | 58 | ## [3.3.2](https://github.com/azu/power-doctest/compare/v3.3.1...v3.3.2) (2019-08-25) 59 | 60 | **Note:** Version bump only for package @power-doctest/markdown 61 | 62 | ## [3.3.1](https://github.com/azu/power-doctest/compare/v3.3.0...v3.3.1) (2019-08-25) 63 | 64 | **Note:** Version bump only for package @power-doctest/markdown 65 | 66 | # [3.3.0](https://github.com/azu/power-doctest/compare/v3.2.1...v3.3.0) (2019-08-25) 67 | 68 | ### Features 69 | 70 | * **power-doctes:** support power-assert again ([09632ec](https://github.com/azu/power-doctest/commit/09632ec)) 71 | 72 | ## [3.2.1](https://github.com/azu/power-doctest/compare/v3.2.0...v3.2.1) (2019-08-25) 73 | 74 | **Note:** Version bump only for package @power-doctest/markdown 75 | 76 | # [3.2.0](https://github.com/azu/power-doctest/compare/v3.1.1...v3.2.0) (2019-08-25) 77 | 78 | ### Features 79 | 80 | * **markdown:** support `runCodeBlockNode` function ([657b1ed](https://github.com/azu/power-doctest/commit/657b1ed)) 81 | 82 | ## [3.1.1](https://github.com/azu/power-doctest/compare/v3.1.0...v3.1.1) (2019-08-25) 83 | 84 | **Note:** Version bump only for package @power-doctest/markdown 85 | 86 | # [3.1.0](https://github.com/azu/power-doctest/compare/v3.0.1...v3.1.0) (2019-08-25) 87 | 88 | ### Features 89 | 90 | * **@power-doctest/markdown:** add lineNumber and columnNumber ([bbc3186](https://github.com/azu/power-doctest/commit/bbc3186)) 91 | 92 | ## [3.0.1](https://github.com/azu/power-doctest/compare/v3.0.0...v3.0.1) (2019-08-25) 93 | 94 | ### Bug Fixes 95 | 96 | * **@power-doctest:** fix main ([c2baef9](https://github.com/azu/power-doctest/commit/c2baef9)) 97 | 98 | # 3.0.0 (2019-08-25) 99 | 100 | ### Features 101 | 102 | * **@power-doctest/markdown:** add @power-doctest/markdown ([d2c8014](https://github.com/azu/power-doctest/commit/d2c8014)) 103 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 azu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/README.md: -------------------------------------------------------------------------------- 1 | # @power-doctest/markdown 2 | 3 | A Markdown parser for power-doctest. 4 | 5 | ## Features 6 | 7 | Run doctest for Markdown's CodeBlock. 8 | 9 | This is markdown example. 10 | Following code is tested by power-doctest. 11 | 12 | 13 | `js` or `javascript` CodeBlock 14 | 15 | ```js 16 | console.log(1); // => 1 17 | ``` 18 | 19 | 20 | ## Install 21 | 22 | Install with [npm](https://www.npmjs.com/): 23 | 24 | npm install @power-doctest/markdown 25 | 26 | ## Usage 27 | 28 | `fixtures/example.md`: 29 | 30 | This Is Markdown 31 | 32 | Valid JavaScript Example: 33 | 34 | ```js 35 | console.log("ok"); // => "ok" 36 | ``` 37 | 38 | Invalid JavaScript Example 39 | 40 | ```js 41 | const array = [1, 2, 3]; 42 | console.log(array); // => [1, 44, 3] 43 | ``` 44 | 45 | Example test code 46 | 47 | ```js 48 | import fs from "fs"; 49 | import path from "path"; 50 | import assert from "assert"; 51 | import { run } from "@power-doctest/markdown"; 52 | 53 | describe("run markdown", function() { 54 | it("is example", () => { 55 | const markdown = fs.readFileSync(path.join(__dirname, "fixtures/example.md"), "utf-8"); 56 | return run(markdown).then(() => { 57 | // pass 58 | }).catch(aggregatedError => { 59 | assert.strictEqual(aggregatedError.message, "Throw 1 error in 2 code blocks"); 60 | assert.strictEqual(aggregatedError.errors.length, 1); 61 | const [error] = aggregatedError.errors; 62 | assert.strictEqual(error.message, ` # default.js:4 63 | 64 | assert.deepStrictEqual(array, [1, 44, 3]) 65 | | | 66 | | [1,44,3] 67 | [1,2,3] 68 | `) 69 | 70 | }); 71 | }); 72 | }); 73 | ``` 74 | 75 | 76 | ## Doctest Control Annotation 77 | 78 | `@power-doctest/markdown` support Doctest Control Annotation as HTML comments. 79 | 80 | ### Disable Doctest: `` 81 | 82 | Disable doctest for the codeblock. 83 | 84 | This code block is not evaluated. 85 | 86 | 87 | ```js 88 | console.log(true); // => "not eval" 89 | ``` 90 | 91 | 92 | ### Expected error: `` 93 | 94 | If the error is not match the result, throw error. 95 | 96 | 97 | ```js 98 | ++++++++; 99 | ``` 100 | 101 | ### Doctest options:` ` 102 | 103 | Pass `options` to `@power-doctest/markdown`. 104 | The inline options is preferred constructor options. 105 | 106 | 107 | ```js 108 | if (1 === 1) { 109 | console.log(1); // => 1 110 | } else{ 111 | console.log(2); // => 2 112 | } 113 | ``` 114 | 115 | ### Metadata: `` 116 | 117 | It is useful for testing original behavior. 118 | 119 | Attach Metadata to error 120 | 121 | 122 | ```javascript 123 | typeof 123n; // => "bigint" 124 | ``` 125 | 126 | And `errors` include `meta` property 127 | 128 | ```json 129 | { 130 | "message": "Throw 1 error in 1 code blocks", 131 | "errors": [ 132 | { 133 | "meta": { 134 | "ECMAScript": 2020 135 | }, 136 | "message": "Identifier directly after number (1:10)" 137 | } 138 | ] 139 | } 140 | ``` 141 | 142 | ## Changelog 143 | 144 | See [Releases page](https://github.com/azu/power-doctest/releases). 145 | 146 | ## Running tests 147 | 148 | Install devDependencies and Run `npm test`: 149 | 150 | npm test 151 | 152 | ## Contributing 153 | 154 | Pull requests and stars are always welcome. 155 | 156 | For bugs and feature requests, [please create an issue](https://github.com/azu/power-doctest/issues). 157 | 158 | 1. Fork it! 159 | 2. Create your feature branch: `git checkout -b my-new-feature` 160 | 3. Commit your changes: `git commit -am 'Add some feature'` 161 | 4. Push to the branch: `git push origin my-new-feature` 162 | 5. Submit a pull request :D 163 | 164 | ## Author 165 | 166 | - [github/azu](https://github.com/azu) 167 | - [twitter/azu_re](https://twitter.com/azu_re) 168 | 169 | ## License 170 | 171 | MIT © azu 172 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@power-doctest/markdown", 3 | "version": "5.3.4", 4 | "description": "A Markdown parser for power-doctest.", 5 | "keywords": [ 6 | "doctest", 7 | "javascript", 8 | "markdown" 9 | ], 10 | "homepage": "https://github.com/azu/power-doctest/tree/master/packages/@power-doctest/markdown/", 11 | "bugs": { 12 | "url": "https://github.com/azu/power-doctest/issues" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/azu/power-doctest.git" 17 | }, 18 | "license": "MIT", 19 | "author": "azu", 20 | "files": [ 21 | "bin/", 22 | "lib/", 23 | "src/" 24 | ], 25 | "main": "lib/index.js", 26 | "types": "lib/index.d.ts", 27 | "directories": { 28 | "lib": "lib", 29 | "test": "test" 30 | }, 31 | "scripts": { 32 | "build": "tsc -p .", 33 | "clean": "rimraf lib/", 34 | "prettier": "prettier --write \"**/*.{js,jsx,ts,tsx,css}\"", 35 | "prepublish": "npm run --if-present build", 36 | "test": "mocha \"test/**/*.ts\"", 37 | "updateSnapshot": "UPDATE_SNAPSHOT=1 npm test", 38 | "watch": "tsc -p . --watch" 39 | }, 40 | "prettier": { 41 | "printWidth": 120, 42 | "singleQuote": false, 43 | "tabWidth": 4 44 | }, 45 | "devDependencies": { 46 | "@types/mocha": "^10.0.1", 47 | "@types/node": "^22.13.8", 48 | "mocha": "^11.1.0", 49 | "prettier": "^3.0.0", 50 | "rimraf": "^6.0.1", 51 | "strip-color": "^0.1.0", 52 | "ts-node": "^10.4.0", 53 | "ts-node-test-register": "^10.0.0", 54 | "typescript": "^5.1.6" 55 | }, 56 | "publishConfig": { 57 | "access": "public" 58 | }, 59 | "dependencies": { 60 | "@power-doctest/javascript": "workspace:^", 61 | "@power-doctest/types": "workspace:^", 62 | "@types/unist": "^3.0.3", 63 | "remark": "^11.0.2", 64 | "unist-util-find-all-between": "^1.0.6", 65 | "unist-util-find-before": "^2.0.5", 66 | "unist-util-parents": "^1.0.3", 67 | "unist-util-select": "^2.0.2" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/src/DocTestController.ts: -------------------------------------------------------------------------------- 1 | // MIT © 2017 azu 2 | "use strict"; 3 | // Support doctest:xxx and doctest-xxx 4 | // doctest:xxx is back compatible syntax. 5 | const DISABLE_PATTERN = /doctest[:-]\s*?disable(:?d)?/; 6 | const ENABLE_PATTERN = /doctest[:-]\s*?enable(:?d)?/; 7 | const DOCTEST_OPTIONS = /doctest[:-]\w*?options:({[^}]+})/; 8 | const DOCTEST_METADATA = /doctest[:-]\w*?meta:({[^}]+})/; 9 | // doctest-error:SyntaxError 10 | const ERROR_TYPE_PATTERN = /(?:doctest|doctest-error):\s*([\w\s]*?Error)/; 11 | 12 | /** 13 | * CodeBlockの手前に該当するHTMLコメントはdoctestの制御コードとして扱える 14 | * 15 | * @example 16 | * 以下のは実行されないのでOKになる 17 | * 18 | * 19 | * ```js 20 | * 1; // => 2 21 | * ``` 22 | * 23 | * @example 24 | * 次はdoctestの結果のError名を指定できる 25 | * 26 | * 27 | * ```js 28 | * NO_DEFINE++; 29 | * ``` 30 | * 31 | * @type {String} 32 | */ 33 | export class DocTestController { 34 | private comments: string[]; 35 | private _expectedErrorName: undefined | string; 36 | 37 | /** 38 | * @param {string[]} comments 39 | */ 40 | constructor(comments: string[]) { 41 | this.comments = comments; 42 | this._expectedErrorName = this._getExpectedErrorName(comments); 43 | } 44 | 45 | /** 46 | * Return state of @power-doctest/types 47 | */ 48 | get state() { 49 | for (const comment of this.comments) { 50 | if (ENABLE_PATTERN.test(comment)) { 51 | return "enabled"; 52 | } else if (DISABLE_PATTERN.test(comment)) { 53 | return "disabled"; 54 | } 55 | } 56 | // not defined 57 | return "none"; 58 | } 59 | 60 | /** 61 | * @returns {string|undefined} 62 | */ 63 | get expectedErrorName() { 64 | return this._expectedErrorName; 65 | } 66 | 67 | /** 68 | * @returns {boolean} 69 | */ 70 | get hasExpectedError() { 71 | return this.expectedErrorName !== undefined; 72 | } 73 | 74 | get doctestMetadata() { 75 | const optionComment = this.comments.find((comment) => { 76 | return DOCTEST_METADATA.test(comment); 77 | }); 78 | if (!optionComment) { 79 | return; 80 | } 81 | const optionString = optionComment.match(DOCTEST_METADATA); 82 | if (!optionString) { 83 | return; 84 | } 85 | try { 86 | return JSON.parse(optionString[1]); 87 | } catch (error) { 88 | throw new Error(`Can not parsed the metadata. 89 | 90 | doctest:metadata:{ ... } should be json string. 91 | 92 | Actual: ${optionString} 93 | `); 94 | } 95 | } 96 | 97 | get doctestOptions() { 98 | const optionComment = this.comments.find((comment) => { 99 | return DOCTEST_OPTIONS.test(comment); 100 | }); 101 | if (!optionComment) { 102 | return; 103 | } 104 | const optionString = optionComment.match(DOCTEST_OPTIONS); 105 | if (!optionString) { 106 | return; 107 | } 108 | try { 109 | return JSON.parse(optionString[1]); 110 | } catch (error) { 111 | throw new Error(`Can not parsed the options. 112 | 113 | doctest:options:{ ... } should be json string. 114 | 115 | Actual: ${optionString} 116 | `); 117 | } 118 | } 119 | 120 | /** 121 | * Return true, if the `error` is expected error name 122 | * If not defined expected error, return true. 123 | * @param {Error} [error] 124 | * @returns {boolean} 125 | */ 126 | isExpectedError(error: Error) { 127 | if (!this.hasExpectedError) { 128 | return false; 129 | } 130 | const expectedErrorType = this.expectedErrorName; 131 | if (!expectedErrorType) { 132 | return true; // no expected error 133 | } 134 | return error.name === expectedErrorType; 135 | } 136 | 137 | /** 138 | * Return expected Error name if expected is defined. 139 | * @returns {string[]} 140 | * @returns {string|undefined} 141 | * @private 142 | */ 143 | _getExpectedErrorName(comments: string[]): string | undefined { 144 | const expectedErrorTypeComment = comments.find((comment) => { 145 | return ERROR_TYPE_PATTERN.test(comment); 146 | }); 147 | if (!expectedErrorTypeComment) { 148 | return; 149 | } 150 | const match = expectedErrorTypeComment.match(ERROR_TYPE_PATTERN); 151 | const matched = match && match[1]; 152 | return matched ? matched : undefined; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/src/index.ts: -------------------------------------------------------------------------------- 1 | import { ParserArgs, ParsedResults } from "@power-doctest/types"; 2 | import { DocTestController } from "./DocTestController"; 3 | 4 | type UnistParentNode = import("unist").Parent; 5 | // unist-util-parents 6 | type UnistNode = import("unist").Node & { 7 | parent: UnistParentNode; 8 | }; 9 | 10 | const remark = require("remark")(); 11 | const select = require("unist-util-select"); 12 | const attachParents = require("unist-util-parents"); 13 | const findAllBetween = require("unist-util-find-all-between"); 14 | const findBefore = require("unist-util-find-before"); 15 | const getComments = (parentNode: UnistParentNode, codeNode: UnistNode) => { 16 | const nonHtmlNode = findBefore(parentNode, codeNode, (node: UnistNode) => { 17 | return node.type !== "html"; 18 | }); 19 | const startNode = nonHtmlNode ? nonHtmlNode : parentNode.children[0]; 20 | const htmlNodes = findAllBetween(parentNode, startNode, codeNode, "html"); 21 | return htmlNodes.map((htmlNode: any) => { 22 | return htmlNode.value.replace(/^$/, ""); 23 | }); 24 | }; 25 | 26 | /** 27 | * Parse Markdown code and return ParseResult object. 28 | */ 29 | export const parse = ({ content, filePath }: ParserArgs): ParsedResults => { 30 | const markdownAST = attachParents(remark.parse(content)); 31 | const codeBlocks = [].concat( 32 | select.selectAll(`code[lang="js"]`, markdownAST), 33 | select.selectAll(`code[lang="javascript"]`, markdownAST) 34 | ); 35 | return codeBlocks.map((codeBlock: UnistNode & { value: string | undefined }) => { 36 | const codeValue: string = codeBlock.value || ""; 37 | const comments = getComments(codeBlock.parent, codeBlock); 38 | const docTestController = new DocTestController(comments); 39 | const state = docTestController.state; 40 | const doctestOptions = docTestController.doctestOptions; 41 | const expectedError = docTestController.expectedErrorName; 42 | const metadata = docTestController.doctestMetadata; 43 | return { 44 | code: codeValue, 45 | location: codeBlock.position 46 | ? { 47 | start: { 48 | line: codeBlock.position.start.line, 49 | column: codeBlock.position.start.column, 50 | }, 51 | end: { 52 | line: codeBlock.position.end.line, 53 | column: codeBlock.position.end.column, 54 | }, 55 | } 56 | : { 57 | start: { 58 | line: 1, 59 | column: 0, 60 | }, 61 | end: { 62 | line: 1, 63 | column: 0, 64 | }, 65 | }, 66 | state: state, 67 | expectedError: expectedError, 68 | metadata: metadata, 69 | doctestOptions: doctestOptions 70 | ? { 71 | filePath: filePath, 72 | ...doctestOptions, 73 | } 74 | : { 75 | filePath, 76 | }, 77 | }; 78 | }); 79 | }; 80 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/fixtures/ng.invalid-options/error.txt: -------------------------------------------------------------------------------- 1 | { 2 | "message": "Throw 1 error in 2 code blocks", 3 | "errors": [ 4 | { 5 | "name": "Error" 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/fixtures/ng.invalid-options/input.md: -------------------------------------------------------------------------------- 1 | Async Code test. 2 | 3 | 4 | ```js 5 | 1; // => 1 6 | ``` 7 | 8 | ```js 9 | 2; // => 2 10 | ``` 11 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshot.test.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import * as path from "path"; 3 | import * as assert from "assert"; 4 | // transform function 5 | import { parse } from "../src"; 6 | 7 | const fixturesDir = path.join(__dirname, "snapshots"); 8 | 9 | const trimUndefinedProperty = (o: T, baseDir: string): T => { 10 | return JSON.parse(stringify(o as {}, baseDir)); 11 | }; 12 | const stringify = (o: {}, baseDir: string): string => { 13 | return JSON.stringify( 14 | o, 15 | (key: string, value: any) => { 16 | if (key === "filePath" && typeof value === "string") { 17 | return path.relative(baseDir, value); 18 | } else { 19 | return value; 20 | } 21 | }, 22 | 4, 23 | ); 24 | }; 25 | describe("Snapshot testing", () => { 26 | fs.readdirSync(fixturesDir).map((caseName) => { 27 | const normalizedTestName = caseName.replace(/-/g, " "); 28 | it(`Test ${normalizedTestName}`, async function () { 29 | const fixtureDir = path.join(fixturesDir, caseName); 30 | const actualFilePath = path.join(fixtureDir, "input.md"); 31 | const actualContent = fs.readFileSync(actualFilePath, "utf-8"); 32 | const results = parse({ 33 | content: actualContent, 34 | filePath: actualFilePath, 35 | }); 36 | const expectedFilePath = path.join(fixtureDir, "output.json"); 37 | // Usage: update snapshots 38 | // UPDATE_SNAPSHOT=1 npm test 39 | if (!fs.existsSync(expectedFilePath) || process.env.UPDATE_SNAPSHOT) { 40 | fs.writeFileSync(expectedFilePath, stringify(results, fixtureDir)); 41 | this.skip(); // skip when updating snapshots 42 | return; 43 | } 44 | // compare input and output 45 | const expectedContent = JSON.parse(fs.readFileSync(expectedFilePath, "utf-8")); 46 | assert.deepStrictEqual(trimUndefinedProperty(results, fixtureDir), expectedContent); 47 | }); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ng.async/input.md: -------------------------------------------------------------------------------- 1 | Async Code test. 2 | 3 | ```js 4 | Promise.resolve(1); // => Resolve: 2 5 | ``` 6 | 7 | `javascript` codeBlock 8 | 9 | ```javascript 10 | setTimeout(() => { 11 | console.log("setTimeout"); // => "???" 12 | }, 100); 13 | ``` 14 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ng.async/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "Promise.resolve(1); // => Resolve: 2", 4 | "location": { 5 | "start": { 6 | "line": 3, 7 | "column": 1 8 | }, 9 | "end": { 10 | "line": 5, 11 | "column": 4 12 | } 13 | }, 14 | "state": "none", 15 | "doctestOptions": { 16 | "filePath": "input.md" 17 | } 18 | }, 19 | { 20 | "code": "setTimeout(() => {\n console.log(\"setTimeout\"); // => \"???\"\n}, 100);", 21 | "location": { 22 | "start": { 23 | "line": 9, 24 | "column": 1 25 | }, 26 | "end": { 27 | "line": 13, 28 | "column": 4 29 | } 30 | }, 31 | "state": "none", 32 | "doctestOptions": { 33 | "filePath": "input.md" 34 | } 35 | } 36 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ng.runMode-all-timeout/input.md: -------------------------------------------------------------------------------- 1 | Expected Error 2 | 3 | 4 | ```js 5 | if (1 === 1) { 6 | console.log(1); // => 1 7 | } else{ 8 | console.log(2); // => 2 9 | } 10 | ``` 11 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ng.runMode-all-timeout/options.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeout": 100 3 | } 4 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ng.runMode-all-timeout/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "if (1 === 1) {\n console.log(1); // => 1\n} else{\n console.log(2); // => 2\n}", 4 | "location": { 5 | "start": { 6 | "line": 4, 7 | "column": 1 8 | }, 9 | "end": { 10 | "line": 10, 11 | "column": 4 12 | } 13 | }, 14 | "state": "none", 15 | "doctestOptions": { 16 | "filePath": "input.md" 17 | } 18 | } 19 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ng.simple/input.md: -------------------------------------------------------------------------------- 1 | This is Markdown. 2 | 3 | `js` CodeBlock 4 | 5 | ```js 6 | console.log(1); // => 2 7 | ``` 8 | 9 | `javascript` codeBlock 10 | 11 | ```javascript 12 | console.log("str"); // => "ng" 13 | ``` 14 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ng.simple/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "console.log(1); // => 2", 4 | "location": { 5 | "start": { 6 | "line": 5, 7 | "column": 1 8 | }, 9 | "end": { 10 | "line": 7, 11 | "column": 4 12 | } 13 | }, 14 | "state": "none", 15 | "doctestOptions": { 16 | "filePath": "input.md" 17 | } 18 | }, 19 | { 20 | "code": "console.log(\"str\"); // => \"ng\"", 21 | "location": { 22 | "start": { 23 | "line": 11, 24 | "column": 1 25 | }, 26 | "end": { 27 | "line": 13, 28 | "column": 4 29 | } 30 | }, 31 | "state": "none", 32 | "doctestOptions": { 33 | "filePath": "input.md" 34 | } 35 | } 36 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ng.with-meta/input.md: -------------------------------------------------------------------------------- 1 | Attach Metadata to error 2 | 3 | 4 | ```javascript 5 | typeof 123n; // => "bigint" 6 | ``` 7 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ng.with-meta/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "typeof 123n; // => \"bigint\"", 4 | "location": { 5 | "start": { 6 | "line": 4, 7 | "column": 1 8 | }, 9 | "end": { 10 | "line": 6, 11 | "column": 4 12 | } 13 | }, 14 | "state": "none", 15 | "metadata": { 16 | "ECMAScript": 2020 17 | }, 18 | "doctestOptions": { 19 | "filePath": "input.md" 20 | } 21 | } 22 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ok.disable/input.md: -------------------------------------------------------------------------------- 1 | This code block is not evaluated. 2 | 3 | 4 | ```js 5 | console.log(true); // => "not eval" 6 | ``` 7 | ``` 8 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ok.disable/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "console.log(true); // => \"not eval\"", 4 | "location": { 5 | "start": { 6 | "line": 4, 7 | "column": 1 8 | }, 9 | "end": { 10 | "line": 6, 11 | "column": 4 12 | } 13 | }, 14 | "state": "disabled", 15 | "doctestOptions": { 16 | "filePath": "input.md" 17 | } 18 | } 19 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ok.doctest-error/input.md: -------------------------------------------------------------------------------- 1 | Expected Error 2 | 3 | 4 | ```js 5 | ++++++++; 6 | ``` 7 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ok.doctest-error/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "++++++++;", 4 | "location": { 5 | "start": { 6 | "line": 4, 7 | "column": 1 8 | }, 9 | "end": { 10 | "line": 6, 11 | "column": 4 12 | } 13 | }, 14 | "state": "none", 15 | "expectedError": "SyntaxError", 16 | "doctestOptions": { 17 | "filePath": "input.md" 18 | } 19 | } 20 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ok.runMode-any/input.md: -------------------------------------------------------------------------------- 1 | Expected Error 2 | 3 | 4 | ```js 5 | if (1 === 1) { 6 | console.log(1); // => 1 7 | } else{ 8 | console.log(2); // => 2 9 | } 10 | ``` 11 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ok.runMode-any/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "if (1 === 1) {\n console.log(1); // => 1\n} else{\n console.log(2); // => 2\n}", 4 | "location": { 5 | "start": { 6 | "line": 4, 7 | "column": 1 8 | }, 9 | "end": { 10 | "line": 10, 11 | "column": 4 12 | } 13 | }, 14 | "state": "none", 15 | "doctestOptions": { 16 | "filePath": "input.md", 17 | "runMode": "any" 18 | } 19 | } 20 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ok.simple/input.md: -------------------------------------------------------------------------------- 1 | This is Markdown. 2 | 3 | `js` CodeBlock 4 | 5 | ```js 6 | console.log(1); // => 1 7 | ``` 8 | 9 | `javascript` codeBlock 10 | 11 | ```javascript 12 | console.log("str"); // => "str" 13 | ``` 14 | -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/snapshots/ok.simple/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "code": "console.log(1); // => 1", 4 | "location": { 5 | "start": { 6 | "line": 5, 7 | "column": 1 8 | }, 9 | "end": { 10 | "line": 7, 11 | "column": 4 12 | } 13 | }, 14 | "state": "none", 15 | "doctestOptions": { 16 | "filePath": "input.md" 17 | } 18 | }, 19 | { 20 | "code": "console.log(\"str\"); // => \"str\"", 21 | "location": { 22 | "start": { 23 | "line": 11, 24 | "column": 1 25 | }, 26 | "end": { 27 | "line": 13, 28 | "column": 4 29 | } 30 | }, 31 | "state": "none", 32 | "doctestOptions": { 33 | "filePath": "input.md" 34 | } 35 | } 36 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "noEmit": true 6 | }, 7 | "include": [ 8 | "../src/**/*", 9 | "./**/*" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/@power-doctest/markdown/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "esModuleInterop": true, 7 | "newLine": "LF", 8 | "outDir": "./lib/", 9 | "target": "es5", 10 | "sourceMap": true, 11 | "declaration": true, 12 | "jsx": "preserve", 13 | "lib": [ 14 | "esnext", 15 | "dom" 16 | ], 17 | /* Strict Type-Checking Options */ 18 | "strict": true, 19 | /* Additional Checks */ 20 | /* Report errors on unused locals. */ 21 | "noUnusedLocals": true, 22 | /* Report errors on unused parameters. */ 23 | "noUnusedParameters": true, 24 | /* Report error when not all code paths in function return a value. */ 25 | "noImplicitReturns": true, 26 | /* Report errors for fallthrough cases in switch statement. */ 27 | "noFallthroughCasesInSwitch": true 28 | }, 29 | "include": [ 30 | "src/**/*" 31 | ], 32 | "exclude": [ 33 | ".git", 34 | "node_modules" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /packages/@power-doctest/tester/.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore/d2c1bb2b9c72ead618c9f6a48280ebc7a8e0dff6/Node.gitignore 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | .env.test 62 | 63 | # parcel-bundler cache (https://parceljs.org/) 64 | .cache 65 | 66 | # next.js build output 67 | .next 68 | 69 | # nuxt.js build output 70 | .nuxt 71 | 72 | # vuepress build output 73 | .vuepress/dist 74 | 75 | # Serverless directories 76 | .serverless/ 77 | 78 | # FuseBox cache 79 | .fusebox/ 80 | 81 | # DynamoDB Local files 82 | .dynamodb/ 83 | 84 | 85 | ### https://raw.github.com/github/gitignore/d2c1bb2b9c72ead618c9f6a48280ebc7a8e0dff6/Global/JetBrains.gitignore 86 | 87 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 88 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 89 | 90 | # User-specific stuff 91 | .idea/**/workspace.xml 92 | .idea/**/tasks.xml 93 | .idea/**/usage.statistics.xml 94 | .idea/**/dictionaries 95 | .idea/**/shelf 96 | 97 | # Generated files 98 | .idea/**/contentModel.xml 99 | 100 | # Sensitive or high-churn files 101 | .idea/**/dataSources/ 102 | .idea/**/dataSources.ids 103 | .idea/**/dataSources.local.xml 104 | .idea/**/sqlDataSources.xml 105 | .idea/**/dynamic.xml 106 | .idea/**/uiDesigner.xml 107 | .idea/**/dbnavigator.xml 108 | 109 | # Gradle 110 | .idea/**/gradle.xml 111 | .idea/**/libraries 112 | 113 | # Gradle and Maven with auto-import 114 | # When using Gradle or Maven with auto-import, you should exclude module files, 115 | # since they will be recreated, and may cause churn. Uncomment if using 116 | # auto-import. 117 | # .idea/modules.xml 118 | # .idea/*.iml 119 | # .idea/modules 120 | 121 | # CMake 122 | cmake-build-*/ 123 | 124 | # Mongo Explorer plugin 125 | .idea/**/mongoSettings.xml 126 | 127 | # File-based project format 128 | *.iws 129 | 130 | # IntelliJ 131 | out/ 132 | 133 | # mpeltonen/sbt-idea plugin 134 | .idea_modules/ 135 | 136 | # JIRA plugin 137 | atlassian-ide-plugin.xml 138 | 139 | # Cursive Clojure plugin 140 | .idea/replstate.xml 141 | 142 | # Crashlytics plugin (for Android Studio and IntelliJ) 143 | com_crashlytics_export_strings.xml 144 | crashlytics.properties 145 | crashlytics-build.properties 146 | fabric.properties 147 | 148 | # Editor-based Rest Client 149 | .idea/httpRequests 150 | 151 | # Android studio 3.1+ serialized cache file 152 | .idea/caches/build_file_checksums.ser 153 | 154 | 155 | /lib 156 | -------------------------------------------------------------------------------- /packages/@power-doctest/tester/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": [ 3 | "ts-node-test-register" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/@power-doctest/tester/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 azu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/@power-doctest/tester/README.md: -------------------------------------------------------------------------------- 1 | # @power-doctest/tester 2 | 3 | A Test Runner for A power-doctest. 4 | 5 | ## Install 6 | 7 | Install with [npm](https://www.npmjs.com/): 8 | 9 | npm install @power-doctest/tester 10 | 11 | ## Usage 12 | 13 | ```js 14 | import { run } from "@power-doctest/tester" 15 | run(` 16 | console.log(1); // => 1 17 | console.log("string"); // => "string" 18 | console.log([1, 2, 3]); // => [1, 2, 3] 19 | console.log({ key: "value" }); // => { key: "value" } 20 | console.log(NaN); // => NaN 21 | console.log(null); // => null 22 | // Special Case 23 | throw new Error("message"); // => Error: "message" 24 | // Promise 25 | Promise.resolve(1); // => Resolve: 1 26 | Promise.reject(new Error("message")); // => Reject: "message" 27 | `).then(() => { 28 | console.log("Pass"); 29 | }).catch(error => { 30 | console.log("failed"); 31 | }) 32 | ``` 33 | 34 | ## Options 35 | 36 | ```ts 37 | export interface PowerDoctestRunnerOptions { 38 | // pseudo file path for code 39 | filePath?: string; 40 | // sandbox context for code 41 | // context defined global variables 42 | context?: { 43 | [index: string]: any 44 | } 45 | // sandbox require mock for code 46 | requireMock?: { 47 | [index: string]: any 48 | } 49 | // If it is true, console.log output to console 50 | // If you want to mock console, please pass `console` to `context: { console: consoleMock }` 51 | // 52 | // Exception: 53 | // Always suppress console and assertion, because it is converted to assert function 54 | // ``` 55 | // console.log(1); // => 1 56 | // ``` 57 | console?: boolean; 58 | // Timeout millisecond 59 | // Default: 2000 60 | timeout?: number 61 | // Default: all 62 | // If runMode is all, all assertions are finished and resolve it 63 | // If runMode is any, anyone assertion is finished and resolve it 64 | // In Both, anyone is failed and reject it 65 | runMode?: "any" | "all"; 66 | // Internal Option 67 | powerDoctestCallbackFunctionName?: string; 68 | } 69 | ``` 70 | 71 | ## Changelog 72 | 73 | See [Releases page](https://github.com/azu/power-doctest-runner/releases). 74 | 75 | ## Running tests 76 | 77 | Install devDependencies and Run `npm test`: 78 | 79 | npm test 80 | 81 | ## Contributing 82 | 83 | Pull requests and stars are always welcome. 84 | 85 | For bugs and feature requests, [please create an issue](https://github.com/azu/power-doctest-runner/issues). 86 | 87 | 1. Fork it! 88 | 2. Create your feature branch: `git checkout -b my-new-feature` 89 | 3. Commit your changes: `git commit -am 'Add some feature'` 90 | 4. Push to the branch: `git push origin my-new-feature` 91 | 5. Submit a pull request :D 92 | 93 | ## Author 94 | 95 | - [github/azu](https://github.com/azu) 96 | - [twitter/azu_re](https://twitter.com/azu_re) 97 | 98 | ## License 99 | 100 | MIT © azu 101 | -------------------------------------------------------------------------------- /packages/@power-doctest/tester/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@power-doctest/tester", 3 | "version": "5.3.4", 4 | "description": "A Test Runner for A power-doctest.", 5 | "keywords": [ 6 | "doctest", 7 | "node.js", 8 | "testing", 9 | "vm" 10 | ], 11 | "homepage": "https://github.com/azu/power-doctest-runner", 12 | "bugs": { 13 | "url": "https://github.com/azu/power-doctest-runner/issues" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/azu/power-doctest-runner.git" 18 | }, 19 | "license": "MIT", 20 | "author": "azu", 21 | "files": [ 22 | "bin/", 23 | "lib/", 24 | "src/" 25 | ], 26 | "main": "lib/index.js", 27 | "types": "lib/index.d.ts", 28 | "directories": { 29 | "lib": "lib", 30 | "test": "test" 31 | }, 32 | "scripts": { 33 | "build": "tsc -p .", 34 | "prepublish": "npm run --if-present build", 35 | "test": "mocha \"test/**/*.ts\"", 36 | "updateSnapshot": "UPDATE_SNAPSHOT=1 npm test", 37 | "watch": "tsc -p . --watch", 38 | "prettier": "prettier --write \"**/*.{js,jsx,ts,tsx,css}\"" 39 | }, 40 | "dependencies": { 41 | "@power-doctest/core": "workspace:^", 42 | "@power-doctest/types": "workspace:^", 43 | "power-assert": "^1.6.1" 44 | }, 45 | "devDependencies": { 46 | "@power-doctest/javascript": "workspace:^", 47 | "@types/mocha": "^10.0.1", 48 | "@types/node": "^22.13.8", 49 | "husky": "^9.1.7", 50 | "lint-staged": "^15.4.3", 51 | "mocha": "^11.1.0", 52 | "prettier": "^3.0.0", 53 | "promise.allsettled": "^1.0.4", 54 | "strip-color": "^0.1.0", 55 | "ts-node": "^10.4.0", 56 | "ts-node-test-register": "^10.0.0", 57 | "typescript": "^5.1.6" 58 | }, 59 | "prettier": { 60 | "singleQuote": false, 61 | "printWidth": 120, 62 | "tabWidth": 4 63 | }, 64 | "husky": { 65 | "hooks": { 66 | "precommit": "lint-staged" 67 | } 68 | }, 69 | "lint-staged": { 70 | "*.{js,jsx,ts,tsx,css}": [ 71 | "prettier --write", 72 | "git add" 73 | ] 74 | }, 75 | "publishConfig": { 76 | "access": "public" 77 | }, 78 | "gitHead": "f5473fe0c929896882fb8201e23745a9116b1159" 79 | } 80 | -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/index.test.ts: -------------------------------------------------------------------------------- 1 | import { run } from "../src/index"; 2 | import * as assert from "assert"; 3 | 4 | describe("run", () => { 5 | it("run example code", () => { 6 | return run(` 7 | console.log(1); // => 1 8 | console.log(1n); // => 1n 9 | console.log("string"); // => "string" 10 | console.log([1, 2, 3]); // => [1, 2, 3] 11 | console.log({ key: "value" }); // => { key: "value" } 12 | console.log(NaN); // => NaN 13 | console.log(null); // => null 14 | // Special Case 15 | throw new Error("message"); // => Error: "message" 16 | // Promise 17 | Promise.resolve(1); // => Resolve: 1 18 | Promise.reject(new Error("message")); // => Reject: "message" 19 | `); 20 | }); 21 | it("run throw code", () => { 22 | return run(` 23 | throw new Error("message from code"); 24 | `).catch((error) => { 25 | assert.strictEqual(error.message, "message from code"); 26 | }); 27 | }); 28 | it("run sync code with primitive", () => { 29 | return assert.doesNotReject( 30 | run(` 31 | 1 // => 1 32 | `) 33 | ); 34 | }); 35 | it("run sync code with array", () => { 36 | return assert.doesNotReject( 37 | run(` 38 | const array = [1, 2, 3]; 39 | console.log(array); // => [1, 2, 3] 40 | `) 41 | ); 42 | }); 43 | it("run async code with Promise", () => { 44 | return assert.doesNotReject( 45 | run(` 46 | Promise.resolve().then(() => { 47 | console.log(1); // => 1 48 | console.log(2); // => 2 49 | }); 50 | `) 51 | ); 52 | }); 53 | it("run async code with setTimeout", () => { 54 | return assert.doesNotReject( 55 | run(` 56 | setTimeout(() => { 57 | console.log(1); // => 1 58 | console.log(2); // => 2 59 | }, 100); 60 | `) 61 | ); 62 | }); 63 | it("does reject code with promise in async", () => { 64 | return assert.rejects( 65 | run(` 66 | Promise.resolve().then(() => { 67 | console.log(1); // => 2 68 | }) 69 | `), 70 | "should be rejected" 71 | ); 72 | }); 73 | it("does reject code with setTimeout in async", () => { 74 | return assert.rejects( 75 | run(` 76 | setTimeout(() => { 77 | console.log(1); // => 2 78 | }, 100); 79 | `) 80 | ); 81 | }); 82 | 83 | it("does resolve when all asserted", () => { 84 | return assert.doesNotReject( 85 | run(` 86 | 1; // => 1 87 | 2; // => 2 88 | 3; // => 3 89 | `) 90 | ); 91 | }); 92 | it("does resolve when anyone asserted", () => { 93 | return assert.doesNotReject( 94 | run( 95 | ` 96 | 1; // => 1 97 | // anyone is resolve then finish the code 98 | 2; // => "ng" 99 | 3; // => "ng" 100 | `, 101 | { 102 | runMode: "any", 103 | } 104 | ) 105 | ); 106 | }); 107 | it("does timeout because all assertion never called", () => { 108 | return assert.rejects( 109 | run( 110 | ` 111 | if( true ) { 112 | 1; // => 1 113 | } else{ 114 | 2; // => 2 115 | } 116 | `, 117 | { 118 | timeout: 100, // 100ms 119 | } 120 | ) 121 | ); 122 | }); 123 | }); 124 | -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshot.test.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import * as path from "path"; 3 | import * as assert from "assert"; 4 | import { run, test } from "../src"; 5 | import { parse } from "@power-doctest/javascript"; 6 | 7 | const allSettled = require("promise.allsettled"); 8 | const trimUndefinedProperty = (o: T): T => { 9 | return JSON.parse(JSON.stringify(o)); 10 | }; 11 | const normalizeErrorName = (error: string) => { 12 | const match = error.match(/(.*Error)/); 13 | return match && match[1]; 14 | }; 15 | const fixturesDir = path.join(__dirname, "snapshots"); 16 | describe("Snapshot testing", () => { 17 | fs.readdirSync(fixturesDir).map((caseName) => { 18 | const normalizedTestName = caseName.replace(/-/g, " "); 19 | it(`Run ${normalizedTestName}`, async function () { 20 | const fixtureDir = path.join(fixturesDir, caseName); 21 | const actualFilePath = path.join(fixtureDir, "input.js"); 22 | const actualContent = fs.readFileSync(actualFilePath, "utf-8"); 23 | const actualOptionFilePath = path.join(fixtureDir, "options.json"); 24 | const actualOptions = fs.existsSync(actualOptionFilePath) 25 | ? JSON.parse(fs.readFileSync(actualOptionFilePath, "utf-8")) 26 | : {}; 27 | const actual = 28 | (await run(actualContent, actualOptions).catch((error) => { 29 | return normalizeErrorName(error.name); 30 | })) || "NO ERROR"; 31 | const expectedFilePath = path.join(fixtureDir, "error.txt"); 32 | // Usage: update snapshots 33 | // UPDATE_SNAPSHOT=1 npm test 34 | if (!fs.existsSync(expectedFilePath) || process.env.UPDATE_SNAPSHOT) { 35 | fs.writeFileSync(expectedFilePath, actual); 36 | this.skip(); // skip when updating snapshots 37 | return; 38 | } 39 | // compare input and output 40 | const expectedContent = fs.readFileSync(expectedFilePath, "utf-8"); 41 | assert.deepStrictEqual( 42 | actual, 43 | expectedContent, 44 | ` 45 | ${fixtureDir} 46 | ${actual} 47 | ` 48 | ); 49 | }); 50 | it(`Test ${normalizedTestName}`, async function () { 51 | const fixtureDir = path.join(fixturesDir, caseName); 52 | const actualFilePath = path.join(fixtureDir, "input.js"); 53 | const actualContent = fs.readFileSync(actualFilePath, "utf-8"); 54 | const parsedResults = parse({ 55 | content: actualContent, 56 | filePath: actualFilePath, 57 | }); 58 | const promises = parsedResults.map((result) => { 59 | return test(result); 60 | }); 61 | const actual = await allSettled(promises); 62 | const results = trimUndefinedProperty( 63 | actual.map((result: any) => { 64 | if (result.status === "rejected") { 65 | return { 66 | status: result.status, 67 | message: normalizeErrorName(result.reason.name), 68 | }; 69 | } 70 | return result; 71 | }) 72 | ); 73 | const expectedFilePath = path.join(fixtureDir, "output.json"); 74 | // Usage: update snapshots 75 | // UPDATE_SNAPSHOT=1 npm test 76 | if (!fs.existsSync(expectedFilePath) || process.env.UPDATE_SNAPSHOT) { 77 | fs.writeFileSync(expectedFilePath, JSON.stringify(results, null, 4)); 78 | this.skip(); // skip when updating snapshots 79 | return; 80 | } 81 | // compare input and output 82 | const expectedContent = JSON.parse(fs.readFileSync(expectedFilePath, "utf-8")); 83 | assert.deepStrictEqual(results, expectedContent); 84 | }); 85 | }); 86 | }); 87 | -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/error.array/error.txt: -------------------------------------------------------------------------------- 1 | AssertionError -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/error.array/input.js: -------------------------------------------------------------------------------- 1 | const array = [1, 2, 3]; 2 | console.log(array); // => [3, 4, 5] 3 | -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/error.array/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "status": "rejected", 4 | "message": "AssertionError" 5 | } 6 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/error.async/error.txt: -------------------------------------------------------------------------------- 1 | AssertionError -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/error.async/input.js: -------------------------------------------------------------------------------- 1 | setTimeout(() => { 2 | console.log("setTimeout"); // => "???" 3 | }, 16); 4 | -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/error.async/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "status": "rejected", 4 | "message": "AssertionError" 5 | } 6 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/error.object/error.txt: -------------------------------------------------------------------------------- 1 | AssertionError -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/error.object/input.js: -------------------------------------------------------------------------------- 1 | const array = { a: 1 }; 2 | console.log(array); // => {b: 2} 3 | -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/error.object/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "status": "rejected", 4 | "message": "AssertionError" 5 | } 6 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/ok.array/error.txt: -------------------------------------------------------------------------------- 1 | NO ERROR -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/ok.array/input.js: -------------------------------------------------------------------------------- 1 | const array = [1, 2, 3]; 2 | console.log(array); // => [1,2,3] 3 | -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/ok.array/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "status": "fulfilled" 4 | } 5 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/ok.no-assert/error.txt: -------------------------------------------------------------------------------- 1 | NO ERROR -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/ok.no-assert/input.js: -------------------------------------------------------------------------------- 1 | const value = "no assert code"; 2 | -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/ok.no-assert/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "status": "fulfilled" 4 | } 5 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/ok.private-field/error.txt: -------------------------------------------------------------------------------- 1 | NO ERROR -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/ok.private-field/input.js: -------------------------------------------------------------------------------- 1 | class PrivateExampleClass { 2 | #privateField = 42; 3 | dump() { 4 | console.log(this.#privateField); // => 42 5 | } 6 | } 7 | const privateExample = new PrivateExampleClass(); 8 | privateExample.dump(); 9 | -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/snapshots/ok.private-field/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "status": "fulfilled" 4 | } 5 | ] -------------------------------------------------------------------------------- /packages/@power-doctest/tester/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "noEmit": true 6 | }, 7 | "include": [ 8 | "../src/**/*", 9 | "./**/*" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/@power-doctest/tester/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "esModuleInterop": true, 7 | "newLine": "LF", 8 | "outDir": "./lib/", 9 | "target": "es2015", 10 | "sourceMap": true, 11 | "declaration": true, 12 | "jsx": "preserve", 13 | "lib": [ 14 | "es2018", 15 | "dom" 16 | ], 17 | /* Strict Type-Checking Options */ 18 | "strict": true, 19 | /* Additional Checks */ 20 | /* Report errors on unused locals. */ 21 | "noUnusedLocals": true, 22 | /* Report errors on unused parameters. */ 23 | "noUnusedParameters": true, 24 | /* Report error when not all code paths in function return a value. */ 25 | "noImplicitReturns": true, 26 | /* Report errors for fallthrough cases in switch statement. */ 27 | "noFallthroughCasesInSwitch": true 28 | }, 29 | "include": [ 30 | "src/**/*" 31 | ], 32 | "exclude": [ 33 | ".git", 34 | "node_modules" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /packages/@power-doctest/types/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": [ 3 | "ts-node-test-register" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/@power-doctest/types/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [5.3.3](https://github.com/azu/power-doctest/compare/v5.3.2...v5.3.3) (2023-07-15) 7 | 8 | **Note:** Version bump only for package @power-doctest/types 9 | 10 | 11 | 12 | 13 | 14 | ## [5.3.1](https://github.com/azu/power-doctest/compare/v5.3.0...v5.3.1) (2022-01-05) 15 | 16 | 17 | ### Bug Fixes 18 | 19 | * **deps:** Update babel dependencies to ^7.16.7 ([#28](https://github.com/azu/power-doctest/issues/28)) ([92d68cd](https://github.com/azu/power-doctest/commit/92d68cd8100839cf37c409480a3a932290ff2fbe)) 20 | 21 | 22 | 23 | 24 | 25 | # [5.3.0](https://github.com/azu/power-doctest/compare/v5.2.2...v5.3.0) (2021-05-07) 26 | 27 | 28 | ### Features 29 | 30 | * **deps:** support numeric separator ([#26](https://github.com/azu/power-doctest/issues/26)) ([f0ef57b](https://github.com/azu/power-doctest/commit/f0ef57b02e767576dde6a81582025a9f19db1143)) 31 | 32 | 33 | 34 | 35 | 36 | # [5.2.0](https://github.com/azu/power-doctest/compare/v5.1.3...v5.2.0) (2020-06-20) 37 | 38 | 39 | ### Features 40 | 41 | * **power-doctest:** support ES2020 ([ef624cb](https://github.com/azu/power-doctest/commit/ef624cb9312d62a69b72dcbbbff589557f9b93e5)) 42 | 43 | 44 | 45 | 46 | 47 | ## [5.0.1](https://github.com/azu/power-doctest/compare/v5.0.0...v5.0.1) (2019-09-01) 48 | 49 | **Note:** Version bump only for package @power-doctest/types 50 | 51 | 52 | 53 | 54 | 55 | # [5.0.0](https://github.com/azu/power-doctest/compare/v4.1.2...v5.0.0) (2019-09-01) 56 | 57 | **Note:** Version bump only for package @power-doctest/types 58 | 59 | 60 | 61 | 62 | 63 | # [4.0.0](https://github.com/azu/power-doctest/compare/v3.3.3...v4.0.0) (2019-09-01) 64 | 65 | **Note:** Version bump only for package @power-doctest/types 66 | -------------------------------------------------------------------------------- /packages/@power-doctest/types/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 azu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/@power-doctest/types/README.md: -------------------------------------------------------------------------------- 1 | # @power-doctest/types 2 | 3 | Shared types of @power-doctest 4 | 5 | ## Install 6 | 7 | Install with [npm](https://www.npmjs.com/): 8 | 9 | npm install @power-doctest/types 10 | 11 | ## Usage 12 | 13 | - [ ] Write usage instructions 14 | 15 | ## Changelog 16 | 17 | See [Releases page](https://github.com/azu/power-doctest/releases). 18 | 19 | ## Running tests 20 | 21 | Install devDependencies and Run `npm test`: 22 | 23 | npm test 24 | 25 | ## Contributing 26 | 27 | Pull requests and stars are always welcome. 28 | 29 | For bugs and feature requests, [please create an issue](https://github.com/azu/power-doctest/issues). 30 | 31 | 1. Fork it! 32 | 2. Create your feature branch: `git checkout -b my-new-feature` 33 | 3. Commit your changes: `git commit -am 'Add some feature'` 34 | 4. Push to the branch: `git push origin my-new-feature` 35 | 5. Submit a pull request :D 36 | 37 | ## Author 38 | 39 | - [github/azu](https://github.com/azu) 40 | - [twitter/azu_re](https://twitter.com/azu_re) 41 | 42 | ## License 43 | 44 | MIT © azu 45 | -------------------------------------------------------------------------------- /packages/@power-doctest/types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@power-doctest/types", 3 | "version": "5.3.4", 4 | "description": "Shared types of @power-doctest", 5 | "keywords": [ 6 | "types", 7 | "typescript" 8 | ], 9 | "homepage": "https://github.com/azu/power-doctest/tree/master/packages/@power-doctest/types/", 10 | "bugs": { 11 | "url": "https://github.com/azu/power-doctest/issues" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/azu/power-doctest.git" 16 | }, 17 | "license": "MIT", 18 | "author": "azu", 19 | "files": [ 20 | "bin/", 21 | "lib/", 22 | "src/" 23 | ], 24 | "main": "lib/index.js", 25 | "types": "lib/index.d.ts", 26 | "directories": { 27 | "lib": "lib", 28 | "test": "test" 29 | }, 30 | "scripts": { 31 | "build": "tsc -p .", 32 | "clean": "rimraf lib/", 33 | "prettier": "prettier --write \"**/*.{js,jsx,ts,tsx,css}\"", 34 | "prepublish": "npm run --if-present build", 35 | "test": "mocha \"test/**/*.ts\"", 36 | "watch": "tsc -p . --watch" 37 | }, 38 | "prettier": { 39 | "printWidth": 120, 40 | "singleQuote": false, 41 | "tabWidth": 4 42 | }, 43 | "devDependencies": { 44 | "@types/mocha": "^10.0.1", 45 | "@types/node": "^22.13.8", 46 | "mocha": "^11.1.0", 47 | "prettier": "^3.0.0", 48 | "rimraf": "^6.0.1", 49 | "ts-node": "^10.4.0", 50 | "ts-node-test-register": "^10.0.0", 51 | "typescript": "^5.1.6" 52 | }, 53 | "publishConfig": { 54 | "access": "public" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/@power-doctest/types/src/index.ts: -------------------------------------------------------------------------------- 1 | export type ParsedCode = { 2 | code: string; 3 | location: { 4 | start: { 5 | line: number; 6 | column: number; 7 | }; 8 | end: { 9 | line: number; 10 | column: number; 11 | }; 12 | }; 13 | /** 14 | * If it is "none", use default state of tester 15 | */ 16 | state: "enabled" | "disabled" | "none"; 17 | expectedError?: "Error" | string; 18 | metadata?: {}; 19 | doctestOptions?: {}; 20 | }; 21 | export type ParsedResults = ParsedCode[]; 22 | export type ParserArgs = { 23 | content: string; 24 | filePath: string; 25 | }; 26 | -------------------------------------------------------------------------------- /packages/@power-doctest/types/test/index.test.ts: -------------------------------------------------------------------------------- 1 | import { ParsedResults, ParsedCode, ParserArgs } from "../src"; 2 | 3 | it("is valid types", () => { 4 | const parse = (args: ParserArgs): ParsedResults => { 5 | const code: ParsedCode = { 6 | code: args.content, 7 | state: "none", 8 | location: { 9 | start: { 10 | line: 1, 11 | column: 0, 12 | }, 13 | end: { 14 | line: 1, 15 | column: 0, 16 | }, 17 | }, 18 | }; 19 | return [code]; 20 | }; 21 | parse({ 22 | content: "test", 23 | filePath: "test.md", 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /packages/@power-doctest/types/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "noEmit": true 6 | }, 7 | "include": [ 8 | "../src/**/*", 9 | "./**/*" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/@power-doctest/types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "esModuleInterop": true, 7 | "newLine": "LF", 8 | "outDir": "./lib/", 9 | "target": "es5", 10 | "sourceMap": true, 11 | "declaration": true, 12 | "jsx": "preserve", 13 | "lib": [ 14 | "esnext", 15 | "dom" 16 | ], 17 | /* Strict Type-Checking Options */ 18 | "strict": true, 19 | /* Additional Checks */ 20 | /* Report errors on unused locals. */ 21 | "noUnusedLocals": true, 22 | /* Report errors on unused parameters. */ 23 | "noUnusedParameters": true, 24 | /* Report error when not all code paths in function return a value. */ 25 | "noImplicitReturns": true, 26 | /* Report errors for fallthrough cases in switch statement. */ 27 | "noFallthroughCasesInSwitch": true 28 | }, 29 | "include": [ 30 | "src/**/*" 31 | ], 32 | "exclude": [ 33 | ".git", 34 | "node_modules" 35 | ] 36 | } -------------------------------------------------------------------------------- /packages/comment-to-assert/.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore/408c616ae0ad8f4b8101d8e876b9b67ac6b14059/Node.gitignore 2 | 3 | # Logs 4 | logs 5 | *.log 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 19 | .grunt 20 | 21 | # node-waf configuration 22 | .lock-wscript 23 | 24 | # Compiled binary addons (http://nodejs.org/api/addons.html) 25 | build/Release 26 | 27 | # Dependency directory 28 | # Commenting this out is preferred by some people, see 29 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 30 | node_modules 31 | 32 | 33 | ### https://raw.github.com/github/gitignore/408c616ae0ad8f4b8101d8e876b9b67ac6b14059/Global/JetBrains.gitignore 34 | 35 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 36 | 37 | *.iml 38 | 39 | ## Directory-based project format: 40 | .idea/ 41 | # if you remove the above rule, at least ignore the following: 42 | 43 | # User-specific stuff: 44 | # .idea/workspace.xml 45 | # .idea/tasks.xml 46 | # .idea/dictionaries 47 | 48 | # Sensitive or high-churn files: 49 | # .idea/dataSources.ids 50 | # .idea/dataSources.xml 51 | # .idea/sqlDataSources.xml 52 | # .idea/dynamic.xml 53 | # .idea/uiDesigner.xml 54 | 55 | # Gradle: 56 | # .idea/gradle.xml 57 | # .idea/libraries 58 | 59 | # Mongo Explorer plugin: 60 | # .idea/mongoSettings.xml 61 | 62 | ## File-based project format: 63 | *.ipr 64 | *.iws 65 | 66 | ## Plugin-specific files: 67 | 68 | # IntelliJ 69 | out/ 70 | 71 | # mpeltonen/sbt-idea plugin 72 | .idea_modules/ 73 | 74 | # JIRA plugin 75 | atlassian-ide-plugin.xml 76 | 77 | # Crashlytics plugin (for Android Studio and IntelliJ) 78 | com_crashlytics_export_strings.xml 79 | crashlytics.properties 80 | crashlytics-build.properties 81 | 82 | 83 | 84 | /lib 85 | lib -------------------------------------------------------------------------------- /packages/comment-to-assert/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": [ 3 | "ts-node-test-register" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/comment-to-assert/.prettierignore: -------------------------------------------------------------------------------- 1 | test/snapshots/**/* 2 | -------------------------------------------------------------------------------- /packages/comment-to-assert/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [5.3.3](https://github.com/azu/comment-to-assert/compare/v5.3.2...v5.3.3) (2023-07-15) 7 | 8 | **Note:** Version bump only for package comment-to-assert 9 | 10 | 11 | 12 | 13 | 14 | ## [5.3.1](https://github.com/azu/comment-to-assert/compare/v5.3.0...v5.3.1) (2022-01-05) 15 | 16 | 17 | ### Bug Fixes 18 | 19 | * **deps:** Update babel dependencies to ^7.16.7 ([#28](https://github.com/azu/comment-to-assert/issues/28)) ([92d68cd](https://github.com/azu/comment-to-assert/commit/92d68cd8100839cf37c409480a3a932290ff2fbe)) 20 | 21 | 22 | 23 | 24 | 25 | # [5.3.0](https://github.com/azu/comment-to-assert/compare/v5.2.2...v5.3.0) (2021-05-07) 26 | 27 | 28 | ### Features 29 | 30 | * **deps:** support numeric separator ([#26](https://github.com/azu/comment-to-assert/issues/26)) ([f0ef57b](https://github.com/azu/comment-to-assert/commit/f0ef57b02e767576dde6a81582025a9f19db1143)) 31 | 32 | 33 | 34 | 35 | 36 | # [5.2.0](https://github.com/azu/comment-to-assert/compare/v5.1.3...v5.2.0) (2020-06-20) 37 | 38 | 39 | ### Features 40 | 41 | * **power-doctest:** support ES2020 ([ef624cb](https://github.com/azu/comment-to-assert/commit/ef624cb9312d62a69b72dcbbbff589557f9b93e5)) 42 | 43 | 44 | 45 | 46 | 47 | ## [5.0.1](https://github.com/azu/comment-to-assert/compare/v5.0.0...v5.0.1) (2019-09-01) 48 | 49 | **Note:** Version bump only for package comment-to-assert 50 | 51 | 52 | 53 | 54 | 55 | # [5.0.0](https://github.com/azu/comment-to-assert/compare/v4.1.2...v5.0.0) (2019-09-01) 56 | 57 | **Note:** Version bump only for package comment-to-assert 58 | 59 | 60 | 61 | 62 | 63 | # [4.0.0](https://github.com/azu/comment-to-assert/compare/v3.3.3...v4.0.0) (2019-09-01) 64 | 65 | **Note:** Version bump only for package comment-to-assert 66 | 67 | 68 | 69 | 70 | 71 | # [3.3.0](https://github.com/azu/comment-to-assert/compare/v3.2.1...v3.3.0) (2019-08-25) 72 | 73 | 74 | ### Features 75 | 76 | * **power-doctes:** support power-assert again ([09632ec](https://github.com/azu/comment-to-assert/commit/09632ec)) 77 | 78 | 79 | 80 | 81 | 82 | # 3.0.0 (2019-08-25) 83 | 84 | 85 | ### Bug Fixes 86 | 87 | * **assert:** fix handling of undefined or null ([#3](https://github.com/azu/comment-to-assert/issues/3)) ([daed652](https://github.com/azu/comment-to-assert/commit/daed652)) 88 | * **ast:** generate code with comment ([d950164](https://github.com/azu/comment-to-assert/commit/d950164)) 89 | * **error:** can handle ``// => *Error` ([628a26a](https://github.com/azu/comment-to-assert/commit/628a26a)) 90 | * **example:** run example then exit 0 ([c1348bc](https://github.com/azu/comment-to-assert/commit/c1348bc)) 91 | * **example:** use disableSourceMap option ([04c1e32](https://github.com/azu/comment-to-assert/commit/04c1e32)) 92 | * **lib:** fix TypeScript definition ([d32b124](https://github.com/azu/comment-to-assert/commit/d32b124)) 93 | * **node:** console.assert does not throw on Node.js 10 ([6a9a74a](https://github.com/azu/comment-to-assert/commit/6a9a74a)) 94 | * **npm:** fix npm test script ([a90ed9f](https://github.com/azu/comment-to-assert/commit/a90ed9f)) 95 | * **test:** remove undefined method ([333c81c](https://github.com/azu/comment-to-assert/commit/333c81c)) 96 | * **util:** #toAST return AST not Node ([308dbe8](https://github.com/azu/comment-to-assert/commit/308dbe8)) 97 | * **utils:** add missing extractionBody ([3bca03e](https://github.com/azu/comment-to-assert/commit/3bca03e)) 98 | * array and directive string expression support ([1a6efcd](https://github.com/azu/comment-to-assert/commit/1a6efcd)) 99 | * update node types ([6ad0195](https://github.com/azu/comment-to-assert/commit/6ad0195)) 100 | 101 | 102 | ### Features 103 | 104 | * **assert:** use `strictEqual` and `deepStrictEqual` ([#9](https://github.com/azu/comment-to-assert/issues/9)) ([85a4bed](https://github.com/azu/comment-to-assert/commit/85a4bed)), closes [#6](https://github.com/azu/comment-to-assert/issues/6) 105 | * **ast:** implement replace comment with assert ([8925ada](https://github.com/azu/comment-to-assert/commit/8925ada)) 106 | * **ast:** support `asyncCallbackName` option ([#11](https://github.com/azu/comment-to-assert/issues/11)) ([a24e4ec](https://github.com/azu/comment-to-assert/commit/a24e4ec)) 107 | * **ast:** support block comment ([16f3cb2](https://github.com/azu/comment-to-assert/commit/16f3cb2)) 108 | * **ast:** support console api ([e1c7067](https://github.com/azu/comment-to-assert/commit/e1c7067)) 109 | * **bin:** add cli ([73701eb](https://github.com/azu/comment-to-assert/commit/73701eb)) 110 | * **comment:** Support object literal as comment ([9c138c7](https://github.com/azu/comment-to-assert/commit/9c138c7)) 111 | * **error:** support handling `Error: message` ([33f1b70](https://github.com/azu/comment-to-assert/commit/33f1b70)) 112 | * **example:** add example ([de07e6a](https://github.com/azu/comment-to-assert/commit/de07e6a)) 113 | * support NaN assert ([117daeb](https://github.com/azu/comment-to-assert/commit/117daeb)) 114 | * **lib:** Resolve: and Reject: support ([1169542](https://github.com/azu/comment-to-assert/commit/1169542)) 115 | * **options:** support assertBeforeCallbackName and assertAfterCallbackName ([2466b17](https://github.com/azu/comment-to-assert/commit/2466b17)) 116 | * **src:** support Promise comment ([#4](https://github.com/azu/comment-to-assert/issues/4)) ([b7882b5](https://github.com/azu/comment-to-assert/commit/b7882b5)) 117 | * **util:** add #wrapNode function ([36baa81](https://github.com/azu/comment-to-assert/commit/36baa81)) 118 | 119 | 120 | ### BREAKING CHANGES 121 | 122 | * **assert:** assertion is strict by default 123 | -------------------------------------------------------------------------------- /packages/comment-to-assert/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 azu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/comment-to-assert/README.md: -------------------------------------------------------------------------------- 1 | # comment-to-assert 2 | 3 | Convert comment to `assert` function. 4 | 5 | ```js 6 | const foo = 1; 7 | foo;// => 1 8 | ``` 9 | 10 | Convert this to: 11 | 12 | ```js 13 | const foo = 1; 14 | assert.strictEqual(foo, 1); 15 | ``` 16 | 17 | ## Syntax 18 | 19 | This library support following format. 20 | 21 | ```js 22 | expression; // => expected value 23 | ``` 24 | 25 | or 26 | 27 | ```js 28 | console.log(expression); // => expected value 29 | ``` 30 | 31 | **Special handling**: 32 | 33 | Error: 34 | 35 | ```js 36 | throw new Error("message"); // Error: "message" 37 | ``` 38 | 39 | Promise: 40 | 41 | ```js 42 | Promise.resolve(1); // => Resolve: 1 43 | Promise.reject(new Error("message")); // => Reject: message 44 | ``` 45 | 46 | 47 | ## Installation 48 | 49 | npm install comment-to-assert 50 | 51 | ### CLI Installation 52 | 53 | npm install -g comment-to-assert 54 | comment-to-assert target.js > modify.js 55 | 56 | ## Usage 57 | 58 | ### toAssertFromSource(source : string, options: toAssertFromSourceOptions): string 59 | 60 | Return string that transformed source string of arguments. 61 | 62 | ```js 63 | import { 64 | toAssertFromSource, 65 | toAssertFromAST 66 | } from "comment-to-assert" 67 | toAssertFromSource("1;// => 1");// => "assert.equal(1, 1)" 68 | ``` 69 | 70 | `toAssertFromSource` only support transform source code. 71 | if want to source map, should use `toAssertFromAST` with own parser and generator. 72 | 73 | **Options:** 74 | 75 | - `babel`: [@babel/core](https://babeljs.io/docs/en/babel-core) option 76 | 77 | ``` 78 | interface toAssertFromSourceOptions { 79 | babel?: { 80 | plugins: string[]; 81 | }; 82 | } 83 | ``` 84 | 85 | ### toAssertFromAST(AST : object, options: toAssertFromASTOptions): object 86 | 87 | Return AST object that transformed AST of arguments. 88 | 89 | ```js 90 | var AST = parse(`var a = [1]; 91 | a;// => [1]`); 92 | var resultOfAST = toAssertFromAST(AST); 93 | generate(resultOfAST); 94 | /* 95 | var a = [1]; 96 | assert.deepEqual(a, [1]); 97 | */ 98 | ``` 99 | 100 | 101 | **Options:** 102 | 103 | - `assertBeforeCallbackName`: callback name before assertion 104 | - `assertAfterCallbackName`: callback name after assertion 105 | 106 | ``` 107 | export interface toAssertFromASTOptions { 108 | assertBeforeCallbackName?: string; 109 | assertAfterCallbackName?: string; 110 | } 111 | ``` 112 | 113 | ```js 114 | 1; // => 1 115 | "str"; // => "str" 116 | [1, 2, 3]; // => [1,2,3] 117 | Promise.resolve(1); // => Resolve: 1 118 | ``` 119 | 120 | to be 121 | 122 | ```js 123 | beforeCallback("id:0"); 124 | assert.strictEqual(1, 1); 125 | afterCallback("id:0"); 126 | // => 1 127 | beforeCallback("id:1"); 128 | assert.strictEqual("str", "str"); 129 | afterCallback("id:1"); 130 | // => "str" 131 | beforeCallback("id:2"); 132 | assert.deepStrictEqual([1, 2, 3], [1, 2, 3]); 133 | afterCallback("id:2"); 134 | // => [1,2,3] 135 | Promise.resolve(Promise.resolve(1)).then(v => { 136 | beforeCallback("id:3"); 137 | assert.strictEqual(v, 1); 138 | afterCallback("id:3"); 139 | return v; 140 | }); // => Resolve: 1 141 | ``` 142 | 143 | ### Example 144 | 145 | See [example/](example/) 146 | 147 | ``` 148 | "use strict"; 149 | var assert = require("assert"); 150 | var toAssertFromSource = require("comment-to-assert").toAssertFromSource; 151 | toAssertFromSource("1;// => 1");// => 'assert.equal(1, 1);' 152 | toAssertFromSource("[1];// => [1]");// => 'assert.deepEqual([1], [1]);' 153 | toAssertFromSource("var foo=1;foo;// => 1");// => 'var foo = 1;\nassert.equal(foo, 1);' 154 | ``` 155 | 156 | ## Tests 157 | 158 | npm test 159 | 160 | Update snapshots if you need. 161 | 162 | npm run updateSnapshot 163 | 164 | ## Contributing 165 | 166 | 1. Fork it! 167 | 2. Create your feature branch: `git checkout -b my-new-feature` 168 | 3. Commit your changes: `git commit -am 'Add some feature'` 169 | 4. Push to the branch: `git push origin my-new-feature` 170 | 5. Submit a pull request :D 171 | 172 | ## License 173 | 174 | MIT 175 | -------------------------------------------------------------------------------- /packages/comment-to-assert/bin/cmd.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var toAssert = require("../").toAssertFromSource; 3 | var concat = require("concat-stream"); 4 | var fs = require("fs"); 5 | var path = require("path"); 6 | var file = process.argv[2]; 7 | var input = file && file !== "-" ? fs.createReadStream(process.argv[2]) : process.stdin; 8 | input.pipe( 9 | concat(function (buf) { 10 | var filePath = path.join(process.cwd(), file); 11 | console.log(toAssert(buf.toString("utf8"), filePath)); 12 | }) 13 | ); 14 | -------------------------------------------------------------------------------- /packages/comment-to-assert/example/example.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | var assert = require("assert"); 4 | var toAssertFromSource = require("comment-to-assert").toAssertFromSource; 5 | toAssertFromSource("1;// => 1"); // => 'assert.equal(1, 1);' 6 | toAssertFromSource("[1];// => [1]"); // => 'assert.deepEqual([1], [1]);' 7 | toAssertFromSource("var foo=1;foo;// => 1"); // => 'var foo = 1;\nassert.equal(foo, 1);' 8 | -------------------------------------------------------------------------------- /packages/comment-to-assert/example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "npm i && node example.js" 8 | }, 9 | "author": "azu", 10 | "license": "MIT", 11 | "dependencies": { 12 | "comment-to-assert": "file:.." 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/comment-to-assert/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "comment-to-assert", 3 | "version": "5.3.4", 4 | "description": "convert line comment to assert.", 5 | "keywords": [ 6 | "ast", 7 | "doctest", 8 | "testing" 9 | ], 10 | "homepage": "https://github.com/azu/comment-to-assert", 11 | "bugs": { 12 | "url": "https://github.com/azu/comment-to-assert/issues" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/azu/comment-to-assert.git" 17 | }, 18 | "license": "MIT", 19 | "author": "azu", 20 | "files": [ 21 | "lib", 22 | "src", 23 | "bin" 24 | ], 25 | "main": "lib/comment-to-assert.js", 26 | "types": "lib/comment-to-assert.d.ts", 27 | "bin": { 28 | "comment-to-assert": "./bin/cmd.js" 29 | }, 30 | "directories": { 31 | "test": "test" 32 | }, 33 | "scripts": { 34 | "build": "tsc -p .", 35 | "example": "npm i && npm run build && cd example && npm test", 36 | "prepublish": "npm run --if-present build", 37 | "test": "mocha \"test/**/*.ts\"", 38 | "updateSnapshot": "UPDATE_SNAPSHOT=1 npm test", 39 | "watch": "tsc -p . --watch" 40 | }, 41 | "dependencies": { 42 | "@babel/core": "^7.16.7", 43 | "@babel/parser": "^7.16.7", 44 | "@babel/template": "^7.16.7", 45 | "@babel/traverse": "^7.16.7", 46 | "@babel/types": "^7.16.7", 47 | "concat-stream": "^2.0.0", 48 | "structured-source": "^4.0.0" 49 | }, 50 | "devDependencies": { 51 | "@types/babel__core": "^7.1.18", 52 | "@types/babel__generator": "^7.6.4", 53 | "@types/babel__template": "^7.4.1", 54 | "@types/babel__traverse": "^7.14.2", 55 | "@types/mocha": "^10.0.1", 56 | "@types/node": "^22.13.8", 57 | "husky": "^9.1.7", 58 | "lint-staged": "^15.4.3", 59 | "mocha": "^11.1.0", 60 | "prettier": "^3.0.0", 61 | "ts-node": "^10.4.0", 62 | "ts-node-test-register": "^10.0.0", 63 | "typescript": "^5.1.6" 64 | }, 65 | "email": "azuciao@gmail.com", 66 | "lint-staged": { 67 | "*.{ts,tsx,css}": [ 68 | "prettier --write", 69 | "git add" 70 | ] 71 | }, 72 | "husky": { 73 | "hooks": { 74 | "post-commit": "git reset", 75 | "pre-commit": "lint-staged" 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /packages/comment-to-assert/prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 120, 3 | tabWidth: 4, 4 | }; 5 | -------------------------------------------------------------------------------- /packages/comment-to-assert/src/comment-to-assert.ts: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import { 4 | ERROR_COMMENT_PATTERN, 5 | PROMISE_REJECT_COMMENT_PATTERN, 6 | PROMISE_RESOLVE_COMMENT_PATTERN, 7 | tryGetCodeFromComments, 8 | wrapAssert, 9 | wrapAssertOptions, 10 | } from "./ast-utils"; 11 | import { transformFromAstSync, Node } from "@babel/core"; 12 | import { identifier, isExpressionStatement, File } from "@babel/types"; 13 | import { parse, parseExpression, ParserOptions } from "@babel/parser"; 14 | import traverse from "@babel/traverse"; 15 | 16 | function getExpressionNodeFromCommentValue(commentValue: string): { type: string } & { [index: string]: any } { 17 | // trim and remove trailing semicolon; 18 | const message = commentValue.trim().replace(/;$/, ""); 19 | if (ERROR_COMMENT_PATTERN.test(message)) { 20 | const match = message.match(ERROR_COMMENT_PATTERN); 21 | if (!match) { 22 | throw new Error(`Can not Parse: // => Error: "message"`); 23 | } 24 | return identifier(match[1]); 25 | } 26 | if (PROMISE_RESOLVE_COMMENT_PATTERN.test(message)) { 27 | const match = message.match(PROMISE_RESOLVE_COMMENT_PATTERN); 28 | if (!match) { 29 | throw new Error("Can not Parse: // => Resolve: value"); 30 | } 31 | return { 32 | type: "Resolve", 33 | node: getExpressionNodeFromCommentValue(match[1]), 34 | }; 35 | } else if (PROMISE_REJECT_COMMENT_PATTERN.test(message)) { 36 | const match = message.match(PROMISE_REJECT_COMMENT_PATTERN); 37 | if (!match) { 38 | throw new Error("Can not Parse: // => Reject: value"); 39 | } 40 | return { 41 | type: "Reject", 42 | node: getExpressionNodeFromCommentValue(match[1]), 43 | }; 44 | } 45 | try { 46 | return parseExpression(message); 47 | } catch (e) { 48 | console.error(`Can't parse comments // => expression`); 49 | throw e; 50 | } 51 | } 52 | 53 | export type toAssertFromSourceOptions = { 54 | babel?: ParserOptions; 55 | } & wrapAssertOptions; 56 | 57 | /** 58 | * transform code to asserted code 59 | * if want to source map, use toAssertFromAST. 60 | */ 61 | export function toAssertFromSource(code: string, options?: toAssertFromSourceOptions) { 62 | const ast = parse(code, { 63 | // parse in strict mode and allow module declarations 64 | sourceType: "module", 65 | ...(options && options.babel ? options.babel : {}), 66 | }); 67 | if (!ast) { 68 | throw new Error("Can not parse the code"); 69 | } 70 | const output = toAssertFromAST(ast, options); 71 | const babelFileResult = transformFromAstSync(output as Node, code, { comments: true }); 72 | if (!babelFileResult) { 73 | throw new Error("can not generate from ast: " + JSON.stringify(output)); 74 | } 75 | return babelFileResult.code; 76 | } 77 | 78 | /** 79 | * transform AST to asserted AST. 80 | */ 81 | export function toAssertFromAST(ast: T, options: wrapAssertOptions = {}): T { 82 | const replaceSet = new Set(); 83 | let id = 0; 84 | traverse(ast, { 85 | exit(path) { 86 | if (!replaceSet.has(path.node) && path.node.trailingComments) { 87 | const commentExpression = tryGetCodeFromComments(path.node.trailingComments); 88 | if (commentExpression) { 89 | const commentExpressionNode = getExpressionNodeFromCommentValue(commentExpression); 90 | const actualNode = isExpressionStatement(path.node) ? path.node.expression : path.node; 91 | const replacement = wrapAssert( 92 | { 93 | actualNode: actualNode, 94 | expectedNode: commentExpressionNode, 95 | commentExpression, 96 | id: String(`id:${id++}`), 97 | }, 98 | options, 99 | ); 100 | if (Array.isArray(replacement)) { 101 | // prevent ∞ loopf 102 | path.node.trailingComments = null; 103 | path.replaceWithMultiple(replacement); 104 | } else { 105 | path.replaceWith(replacement); 106 | } 107 | replaceSet.add(path.node); 108 | } 109 | } 110 | }, 111 | }); 112 | return ast; 113 | } 114 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/comment-to-assert-test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from "assert"; 2 | import { toAssertFromSource } from "../src/comment-to-assert"; 3 | 4 | describe("comment-to-assert", function () { 5 | describe("when invalid source", function () { 6 | it("should throw error", function () { 7 | assert.throws(() => { 8 | const code = "++++++"; 9 | toAssertFromSource(code); 10 | }); 11 | }); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshot-test.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import * as path from "path"; 3 | import * as assert from "assert"; 4 | import * as vm from "vm"; 5 | import { toAssertFromSource } from "../src/comment-to-assert"; 6 | 7 | const fixturesDir = path.join(__dirname, "snapshots"); 8 | const trim = (s: unknown): string => { 9 | return typeof s === "string" ? s.trim() : ""; 10 | }; 11 | 12 | describe("Snapshot testing", () => { 13 | fs.readdirSync(fixturesDir).map((caseName) => { 14 | const normalizedTestName = caseName.replace(/-/g, " "); 15 | it(`Test ${normalizedTestName}`, function (done) { 16 | const fixtureDir = path.join(fixturesDir, caseName); 17 | const actualFilePath = path.join(fixtureDir, "input.js"); 18 | const actualContent = fs.readFileSync(actualFilePath, "utf-8"); 19 | const optionFilePath = path.join(fixtureDir, "options.js"); 20 | const options = fs.existsSync(optionFilePath) ? require(optionFilePath) : {}; 21 | const actual = toAssertFromSource(actualContent, options); 22 | const expectedFilePath = path.join(fixtureDir, "output.js"); 23 | // UPDATE_SNAPSHOT=1 npm test 24 | if (!fs.existsSync(expectedFilePath) || process.env.UPDATE_SNAPSHOT) { 25 | fs.writeFileSync(expectedFilePath, String(actual)); 26 | this.skip(); 27 | return; 28 | } 29 | const expected = fs.readFileSync(expectedFilePath, "utf-8"); 30 | assert.deepStrictEqual( 31 | trim(actual), 32 | trim(expected), 33 | ` 34 | ${fixtureDir} 35 | ${JSON.stringify(actual)} 36 | ` 37 | ); 38 | if (typeof actual !== "string") { 39 | throw new Error("actual is not string"); 40 | } 41 | if (options.assertAfterCallbackName && options.assertBeforeCallbackName) { 42 | // finish after all called 43 | let actualCallCount = 0; 44 | const totalCountOfAssert = actual.split(options.assertBeforeCallbackName).length - 1; 45 | vm.runInContext( 46 | actual, 47 | vm.createContext({ 48 | assert, 49 | [options.assertBeforeCallbackName]: () => { 50 | // nope 51 | }, 52 | [options.assertAfterCallbackName]: () => { 53 | actualCallCount++; 54 | if (actualCallCount === totalCountOfAssert) { 55 | done(); 56 | } 57 | }, 58 | }) 59 | ); 60 | } else { 61 | vm.runInContext( 62 | actual, 63 | vm.createContext({ 64 | assert, 65 | }) 66 | ); 67 | done(); 68 | } 69 | }); 70 | }); 71 | }); 72 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/Array-strings/input.js: -------------------------------------------------------------------------------- 1 | const array = ["A", "B", "C"]; 2 | array.unshift("S"); // "S"を先頭に追加 3 | console.log(array); // => ["S", "A", "B", "C"] 4 | const shiftedItem = array.shift(); // 先頭の要素を削除 5 | console.log(shiftedItem); // => "S" 6 | console.log(array); // => ["A", "B", "C"] 7 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/Array-strings/output.js: -------------------------------------------------------------------------------- 1 | const array = ["A", "B", "C"]; 2 | array.unshift("S"); // "S"を先頭に追加 3 | assert.deepStrictEqual(array, ["S", "A", "B", "C"]); // => ["S", "A", "B", "C"] 4 | const shiftedItem = array.shift(); // 先頭の要素を削除 5 | assert.strictEqual(shiftedItem, "S"); // => "S" 6 | assert.deepStrictEqual(array, ["A", "B", "C"]); // => ["A", "B", "C"] -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/Array/input.js: -------------------------------------------------------------------------------- 1 | var a = [1]; 2 | a; // => [1] 3 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/Array/output.js: -------------------------------------------------------------------------------- 1 | var a = [1]; 2 | assert.deepStrictEqual(a, [1]); // => [1] -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/BinaryExpression/input.js: -------------------------------------------------------------------------------- 1 | var a = function() { 2 | return 1; 3 | }; 4 | a() + 1; // => 2 5 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/BinaryExpression/output.js: -------------------------------------------------------------------------------- 1 | var a = function () { 2 | return 1; 3 | }; 4 | assert.strictEqual(a() + 1, 2); // => 2 -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/BlockComent/input.js: -------------------------------------------------------------------------------- 1 | 1; /* => 1 */ 2 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/BlockComent/output.js: -------------------------------------------------------------------------------- 1 | assert.strictEqual(1, 1); 2 | /* => 1 */ -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/CallExpression/input.js: -------------------------------------------------------------------------------- 1 | var a = function() { 2 | return 1; 3 | }; 4 | a(); // => 1 5 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/CallExpression/output.js: -------------------------------------------------------------------------------- 1 | var a = function () { 2 | return 1; 3 | }; 4 | assert.strictEqual(a(), 1); // => 1 -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/ConsoleLog/input.js: -------------------------------------------------------------------------------- 1 | console.log(null); // => null 2 | console.log(1); // => 1 3 | const a = "str"; 4 | console.log(a); // => "str" 5 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/ConsoleLog/output.js: -------------------------------------------------------------------------------- 1 | assert.strictEqual(null, null); // => null 2 | assert.strictEqual(1, 1); // => 1 3 | const a = "str"; 4 | assert.strictEqual(a, "str"); // => "str" -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/NaN/input.js: -------------------------------------------------------------------------------- 1 | NaN; // => NaN 2 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/NaN/output.js: -------------------------------------------------------------------------------- 1 | assert.ok(isNaN(NaN)); // => NaN -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/Number-String/input.js: -------------------------------------------------------------------------------- 1 | console.log(0b0000000000000000000000000001001); // => 9 2 | // Number#toStringメソッドを使うことで2進数表記の文字列を取得できる 3 | console.log((9).toString(2)); // => "1001" 4 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/Number-String/output.js: -------------------------------------------------------------------------------- 1 | assert.strictEqual(0b0000000000000000000000000001001, 9); // => 9 2 | // Number#toStringメソッドを使うことで2進数表記の文字列を取得できる 3 | assert.strictEqual(9 .toString(2), "1001"); // => "1001" -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/Promise.reject/input.js: -------------------------------------------------------------------------------- 1 | Promise.reject(new Error("message")); // => Reject: "message" 2 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/Promise.reject/output.js: -------------------------------------------------------------------------------- 1 | assert.rejects(Promise.reject(new Error("message"))).then(() => {}); // => Reject: "message" -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/Promise.resolve/input.js: -------------------------------------------------------------------------------- 1 | Promise.resolve(1); // => Resolve: 1 2 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/Promise.resolve/output.js: -------------------------------------------------------------------------------- 1 | Promise.resolve(Promise.resolve(1)).then(v => { 2 | assert.strictEqual(v, 1); 3 | return v; 4 | }); // => Resolve: 1 -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/ThrowError-message/input.js: -------------------------------------------------------------------------------- 1 | throw new Error("x is not defined"); // => ReferenceError: x is not defined 2 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/ThrowError-message/output.js: -------------------------------------------------------------------------------- 1 | assert.throws(function () { 2 | throw new Error("x is not defined"); 3 | }); // => ReferenceError: x is not defined -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/ThrowError/input.js: -------------------------------------------------------------------------------- 1 | throw new Error("error"); // => Error 2 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/ThrowError/output.js: -------------------------------------------------------------------------------- 1 | assert.throws(function () { 2 | throw new Error("error"); 3 | }); // => Error -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/callback.NaN/input.js: -------------------------------------------------------------------------------- 1 | NaN; // => NaN 2 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/callback.NaN/options.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | assertBeforeCallbackName: "beforeCallback", 3 | assertAfterCallbackName: "afterCallback" 4 | }; 5 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/callback.NaN/output.js: -------------------------------------------------------------------------------- 1 | beforeCallback("id:0"); 2 | assert.ok(isNaN(NaN)); 3 | afterCallback("id:0"); -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/callback.multiple-assert/input.js: -------------------------------------------------------------------------------- 1 | 1; // => 1 2 | ("str"); // => "str" 3 | [1, 2, 3]; // => [1,2,3] 4 | Promise.resolve(1); // => Resolve: 1 5 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/callback.multiple-assert/options.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | assertBeforeCallbackName: "beforeCallback", 3 | assertAfterCallbackName: "afterCallback" 4 | }; 5 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/callback.multiple-assert/output.js: -------------------------------------------------------------------------------- 1 | beforeCallback("id:0"); 2 | assert.strictEqual(1, 1); 3 | afterCallback("id:0"); 4 | // => 1 5 | beforeCallback("id:1"); 6 | assert.strictEqual("str", "str"); 7 | afterCallback("id:1"); 8 | // => "str" 9 | beforeCallback("id:2"); 10 | assert.deepStrictEqual([1, 2, 3], [1, 2, 3]); 11 | afterCallback("id:2"); 12 | // => [1,2,3] 13 | Promise.resolve(Promise.resolve(1)).then(v => { 14 | beforeCallback("id:3"); 15 | assert.strictEqual(v, 1); 16 | afterCallback("id:3"); 17 | return v; 18 | }); // => Resolve: 1 -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/console.log.Promise.resolve/input.js: -------------------------------------------------------------------------------- 1 | console.log(Promise.resolve(1)); // => Resolve: 1 2 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/console.log.Promise.resolve/output.js: -------------------------------------------------------------------------------- 1 | Promise.resolve(Promise.resolve(1)).then(v => { 2 | assert.strictEqual(v, 1); 3 | return v; 4 | }); // => Resolve: 1 -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/directive-string-prologue/input.js: -------------------------------------------------------------------------------- 1 | "文字列"; // => "文字列" 2 | "\u6587\u5b57\u5217"; // => "文字列" 3 | "𩸽"[0]; // => "\uD867" 4 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/directive-string-prologue/output.js: -------------------------------------------------------------------------------- 1 | assert.strictEqual("文字列", "文字列"); // => "文字列" 2 | assert.strictEqual("\u6587\u5b57\u5217", "文字列"); // => "文字列" 3 | assert.strictEqual("𩸽"[0], "\uD867"); // => "\uD867" -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/multiple-comments/input.js: -------------------------------------------------------------------------------- 1 | 1; // => 1 2 | 2; // => 2 3 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/multiple-comments/output.js: -------------------------------------------------------------------------------- 1 | assert.strictEqual(1, 1); // => 1 2 | assert.strictEqual(2, 2); // => 2 -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/no-rewrite-single-var-comment/input.js: -------------------------------------------------------------------------------- 1 | var a = 1; // comment 2 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/no-rewrite-single-var-comment/output.js: -------------------------------------------------------------------------------- 1 | var a = 1; // comment -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/no-rewrite-single-var/input.js: -------------------------------------------------------------------------------- 1 | var a = 1; 2 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/no-rewrite-single-var/output.js: -------------------------------------------------------------------------------- 1 | var a = 1; -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/null-literal/input.js: -------------------------------------------------------------------------------- 1 | null; // => null 2 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/null-literal/output.js: -------------------------------------------------------------------------------- 1 | assert.strictEqual(null, null); // => null -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/number-literal/input.js: -------------------------------------------------------------------------------- 1 | 1; // => 1 2 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/number-literal/output.js: -------------------------------------------------------------------------------- 1 | assert.strictEqual(1, 1); // => 1 -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/numeric-separator/input.js: -------------------------------------------------------------------------------- 1 | 1_1_1_1; // => 1_1_1_1 2 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/numeric-separator/output.js: -------------------------------------------------------------------------------- 1 | assert.strictEqual(1_1_1_1, 1_1_1_1); // => 1_1_1_1 -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/string-literal/input.js: -------------------------------------------------------------------------------- 1 | // avoid to directive literal 2 | ("str"); // =>"str" 3 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/string-literal/output.js: -------------------------------------------------------------------------------- 1 | // avoid to directive literal 2 | assert.strictEqual("str", "str"); // =>"str" -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/undefined/input.js: -------------------------------------------------------------------------------- 1 | undefined; // => undefined 2 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/undefined/output.js: -------------------------------------------------------------------------------- 1 | assert.strictEqual(undefined, undefined); // => undefined -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/variable-expeceted-object/input.js: -------------------------------------------------------------------------------- 1 | var a = { a: 1 }; 2 | a; // => { a : 1 } 3 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/variable-expeceted-object/output.js: -------------------------------------------------------------------------------- 1 | var a = { 2 | a: 1 3 | }; 4 | assert.deepStrictEqual(a, { 5 | a: 1 6 | }); // => { a : 1 } -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/variable/input.js: -------------------------------------------------------------------------------- 1 | const a = 1; 2 | a; // => 1 3 | -------------------------------------------------------------------------------- /packages/comment-to-assert/test/snapshots/variable/output.js: -------------------------------------------------------------------------------- 1 | const a = 1; 2 | assert.strictEqual(a, 1); // => 1 -------------------------------------------------------------------------------- /packages/comment-to-assert/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "noEmit": true, 6 | "allowJs": true 7 | }, 8 | "include": [ 9 | "../src/**/*", 10 | "./**/*" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /packages/comment-to-assert/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "esModuleInterop": true, 7 | "newLine": "LF", 8 | "outDir": "./lib/", 9 | "target": "es5", 10 | "sourceMap": true, 11 | "declaration": true, 12 | "jsx": "preserve", 13 | "lib": [ 14 | "esnext", 15 | "dom" 16 | ], 17 | /* Strict Type-Checking Options */ 18 | "strict": true, 19 | /* Additional Checks */ 20 | /* Report errors on unused locals. */ 21 | "noUnusedLocals": true, 22 | /* Report errors on unused parameters. */ 23 | "noUnusedParameters": true, 24 | /* Report error when not all code paths in function return a value. */ 25 | "noImplicitReturns": true, 26 | /* Report errors for fallthrough cases in switch statement. */ 27 | "noFallthroughCasesInSwitch": true 28 | }, 29 | "include": [ 30 | "src/**/*" 31 | ], 32 | "exclude": [ 33 | ".git", 34 | "node_modules" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /packages/power-doctest/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": [ 3 | "ts-node-test-register" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/power-doctest/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [5.3.3](https://github.com/azu/power-doctest/compare/v5.3.2...v5.3.3) (2023-07-15) 7 | 8 | **Note:** Version bump only for package power-doctest 9 | 10 | 11 | 12 | 13 | 14 | ## [5.3.2](https://github.com/azu/power-doctest/compare/v5.3.1...v5.3.2) (2022-05-05) 15 | 16 | **Note:** Version bump only for package power-doctest 17 | 18 | ## [5.3.1](https://github.com/azu/power-doctest/compare/v5.3.0...v5.3.1) (2022-01-05) 19 | 20 | ### Bug Fixes 21 | 22 | * **deps:** Update babel dependencies to ^7.16.7 ([#28](https://github.com/azu/power-doctest/issues/28)) ([92d68cd](https://github.com/azu/power-doctest/commit/92d68cd8100839cf37c409480a3a932290ff2fbe)) 23 | 24 | # [5.3.0](https://github.com/azu/power-doctest/compare/v5.2.2...v5.3.0) (2021-05-07) 25 | 26 | ### Features 27 | 28 | * **deps:** support numeric separator ([#26](https://github.com/azu/power-doctest/issues/26)) ([f0ef57b](https://github.com/azu/power-doctest/commit/f0ef57b02e767576dde6a81582025a9f19db1143)) 29 | 30 | ## [5.2.2](https://github.com/azu/power-doctest/compare/v5.2.1...v5.2.2) (2020-06-20) 31 | 32 | **Note:** Version bump only for package power-doctest 33 | 34 | ## [5.2.1](https://github.com/azu/power-doctest/compare/v5.2.0...v5.2.1) (2020-06-20) 35 | 36 | **Note:** Version bump only for package power-doctest 37 | 38 | # [5.2.0](https://github.com/azu/power-doctest/compare/v5.1.3...v5.2.0) (2020-06-20) 39 | 40 | ### Bug Fixes 41 | 42 | * fix dirname ([7f6c5eb](https://github.com/azu/power-doctest/commit/7f6c5ebe2b0d491ec9d3c4c1357f7dc891865c4b)) 43 | 44 | ### Features 45 | 46 | * **power-doctest:** support ES2020 ([ef624cb](https://github.com/azu/power-doctest/commit/ef624cb9312d62a69b72dcbbbff589557f9b93e5)) 47 | 48 | ## [5.1.3](https://github.com/azu/power-doctest/compare/v5.1.2...v5.1.3) (2019-09-01) 49 | 50 | **Note:** Version bump only for package power-doctest 51 | 52 | ## [5.1.2](https://github.com/azu/power-doctest/compare/v5.1.1...v5.1.2) (2019-09-01) 53 | 54 | ### Bug Fixes 55 | 56 | * **power-assert:** fix README test ([e6af70e](https://github.com/azu/power-doctest/commit/e6af70e)) 57 | 58 | ## [5.1.1](https://github.com/azu/power-doctest/compare/v5.1.0...v5.1.1) (2019-09-01) 59 | 60 | ### Bug Fixes 61 | 62 | * **cli:** rename @power-doctest/cli to power-doctest ([1c5060b](https://github.com/azu/power-doctest/commit/1c5060b)) 63 | 64 | # [5.1.0](https://github.com/azu/power-doctest/compare/v5.0.1...v5.1.0) (2019-09-01) 65 | 66 | ### Features 67 | 68 | * **cli:** support asciidoctor ([4db0637](https://github.com/azu/power-doctest/commit/4db0637)) 69 | 70 | ## [5.0.1](https://github.com/azu/power-doctest/compare/v5.0.0...v5.0.1) (2019-09-01) 71 | 72 | **Note:** Version bump only for package @power-doctest/cli 73 | 74 | # [5.0.0](https://github.com/azu/power-doctest/compare/v4.1.2...v5.0.0) (2019-09-01) 75 | 76 | **Note:** Version bump only for package @power-doctest/cli 77 | 78 | ## [4.1.2](https://github.com/azu/power-doctest/compare/v4.1.1...v4.1.2) (2019-09-01) 79 | 80 | **Note:** Version bump only for package @power-doctest/cli 81 | 82 | # [4.1.0](https://github.com/azu/power-doctest/compare/v4.0.1...v4.1.0) (2019-09-01) 83 | 84 | **Note:** Version bump only for package @power-doctest/cli 85 | 86 | ## [4.0.1](https://github.com/azu/power-doctest/compare/v4.0.0...v4.0.1) (2019-09-01) 87 | 88 | ### Bug Fixes 89 | 90 | * **cli:** add bin field ([dc36805](https://github.com/azu/power-doctest/commit/dc36805)) 91 | 92 | # [4.0.0](https://github.com/azu/power-doctest/compare/v3.3.3...v4.0.0) (2019-09-01) 93 | 94 | ### Bug Fixes 95 | 96 | * fix tester requireMock ([a4e0574](https://github.com/azu/power-doctest/commit/a4e0574)) 97 | 98 | ### Features 99 | 100 | * **cli:** add CLI ([4bb1f7a](https://github.com/azu/power-doctest/commit/4bb1f7a)) 101 | -------------------------------------------------------------------------------- /packages/power-doctest/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 azu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/power-doctest/README.md: -------------------------------------------------------------------------------- 1 | # power-doctest 2 | 3 | A command line tool for power-doctest. 4 | 5 | ## Install 6 | 7 | Install with [npm](https://www.npmjs.com/): 8 | 9 | npm install power-doctest -g 10 | 11 | ## Usage 12 | 13 | ### CLI 14 | 15 | Usage 16 | $ power-doctest /path/to/file.{js,md,adoc} 17 | 18 | Options 19 | --packageDir Current Working directory. Should put package.json in the directory. 20 | --disableRunning Disable running test case that has not state. 21 | 22 | Examples 23 | $ power-doctest ./README.md 24 | $ power-doctest ./README.adoc 25 | $ power-doctest ./src/main.js 26 | 27 | ### Node Modules 28 | 29 | ```js 30 | const { runPowerDoctest } = require("power-doctest"); 31 | runPowerDoctest({ 32 | content: "1; // => 2", 33 | contentType: "javascript", 34 | filePath: "test.js", 35 | disableRunning: false 36 | }).then(results => { 37 | console.log(results[0].status); // => "rejected" 38 | }); 39 | ``` 40 | 41 | ## Changelog 42 | 43 | See [Releases page](https://github.com/azu/power-doctest/releases). 44 | 45 | ## Running tests 46 | 47 | Install devDependencies and Run `npm test`: 48 | 49 | npm test 50 | 51 | ## Contributing 52 | 53 | Pull requests and stars are always welcome. 54 | 55 | For bugs and feature requests, [please create an issue](https://github.com/azu/power-doctest/issues). 56 | 57 | 1. Fork it! 58 | 2. Create your feature branch: `git checkout -b my-new-feature` 59 | 3. Commit your changes: `git commit -am 'Add some feature'` 60 | 4. Push to the branch: `git push origin my-new-feature` 61 | 5. Submit a pull request :D 62 | 63 | ## Author 64 | 65 | - [github/azu](https://github.com/azu) 66 | - [twitter/azu_re](https://twitter.com/azu_re) 67 | 68 | ## License 69 | 70 | MIT © azu 71 | -------------------------------------------------------------------------------- /packages/power-doctest/bin/cmd.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require("../lib/cli") 4 | .run() 5 | .then((result) => { 6 | console.log(result); 7 | }) 8 | .catch((error) => { 9 | console.error(error.message); 10 | process.exit(1); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/power-doctest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "power-doctest", 3 | "version": "5.3.4", 4 | "description": "A command line tool for power-doctest.", 5 | "keywords": [ 6 | "cli", 7 | "doctest", 8 | "javascript", 9 | "npm", 10 | "readme", 11 | "test" 12 | ], 13 | "homepage": "https://github.com/azu/power-doctest/tree/master/packages/@power-doctest/cli/", 14 | "bugs": { 15 | "url": "https://github.com/azu/power-doctest/issues" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/azu/power-doctest.git" 20 | }, 21 | "license": "MIT", 22 | "author": "azu", 23 | "bin": { 24 | "power-doctest": "./bin/cmd.js" 25 | }, 26 | "files": [ 27 | "bin/", 28 | "lib/", 29 | "src/" 30 | ], 31 | "main": "lib/power-doctest.js", 32 | "types": "lib/power-doctest.d.ts", 33 | "directories": { 34 | "lib": "lib", 35 | "test": "test" 36 | }, 37 | "scripts": { 38 | "build": "tsc -p .", 39 | "clean": "rimraf lib/", 40 | "prettier": "prettier --write \"**/*.{js,jsx,ts,tsx,css}\"", 41 | "prepublish": "npm run --if-present build", 42 | "test": "npm run test:unit && npm run test:readme", 43 | "test:unit": "mocha \"test/**/*.ts\"", 44 | "test:readme": "npm run build && ./bin/cmd.js README.md", 45 | "watch": "tsc -p . --watch" 46 | }, 47 | "prettier": { 48 | "printWidth": 120, 49 | "singleQuote": false, 50 | "tabWidth": 4 51 | }, 52 | "devDependencies": { 53 | "@types/mocha": "^10.0.1", 54 | "@types/node": "^22.13.8", 55 | "@types/promise.allsettled": "^1.0.3", 56 | "mocha": "^11.1.0", 57 | "prettier": "^3.0.0", 58 | "rimraf": "^6.0.1", 59 | "ts-node": "^10.4.0", 60 | "ts-node-test-register": "^10.0.0", 61 | "typescript": "^5.1.6" 62 | }, 63 | "publishConfig": { 64 | "access": "public" 65 | }, 66 | "dependencies": { 67 | "@power-doctest/asciidoctor": "workspace:^", 68 | "@power-doctest/javascript": "workspace:^", 69 | "@power-doctest/markdown": "workspace:^", 70 | "@power-doctest/tester": "workspace:^", 71 | "meow": "^5.0.0", 72 | "promise.allsettled": "^1.0.5" 73 | }, 74 | "engines": { 75 | "node": ">=16.17.0" 76 | }, 77 | "gitHead": "f5473fe0c929896882fb8201e23745a9116b1159" 78 | } 79 | -------------------------------------------------------------------------------- /packages/power-doctest/src/cli.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import * as path from "path"; 3 | import { parseArgs } from "node:util"; 4 | import { runPowerDoctest, RunPowerDoctestOption } from "./power-doctest"; 5 | 6 | const USAGE = `Usage: 7 | $ power-doctest /path/to/file.{js,md,adoc} 8 | 9 | Options: 10 | --packageDir Current Working directory. Should put package.json in the directory. 11 | --disableRunning Disable running test case that has not state. 12 | 13 | Examples: 14 | $ power-doctest ./README.md 15 | $ power-doctest ./README.adoc 16 | $ power-doctest ./src/main.js`; 17 | 18 | export async function run() { 19 | const options = { 20 | packageDir: { type: "string" }, 21 | defaultRunning: { type: "boolean" }, 22 | disableRunning: { type: "boolean", default: false }, 23 | } as const; 24 | 25 | const { values: flags, positionals } = parseArgs({ 26 | options, 27 | allowPositionals: true, 28 | }); 29 | 30 | const disableRunning = flags.disableRunning; 31 | const input = positionals[0]; 32 | if (!input) { 33 | console.log(USAGE); 34 | throw new Error("No input file specified. Please provide a file path as an argument."); 35 | } 36 | const content = fs.readFileSync(input, "utf-8"); 37 | const asciidoctExt = [".adoc", ".asc", ".asciidoctor"]; 38 | const markdownFileExts = [".md", ".mkd", ".markdown"]; 39 | const jsFileExts = [".js", ".mjs"]; 40 | const contentType: RunPowerDoctestOption["contentType"] | null = (() => { 41 | const ext = path.extname(input); 42 | if (markdownFileExts.includes(ext)) { 43 | return "markdown"; 44 | } 45 | if (jsFileExts.includes(ext)) { 46 | return "javascript"; 47 | } 48 | if (asciidoctExt.includes(ext)) { 49 | return "asciidoctor"; 50 | } 51 | return null; 52 | })(); 53 | if (!contentType) { 54 | throw new Error("Not supported file type" + input); 55 | } 56 | const cwd = flags.packageDir || process.cwd(); 57 | const pkgFilePath = path.join(cwd, "package.json"); 58 | const pkg = (() => { 59 | try { 60 | return require(pkgFilePath); 61 | } catch (error) { 62 | return; 63 | } 64 | })(); 65 | const results = await runPowerDoctest({ 66 | content, 67 | contentType, 68 | packageDir: cwd, 69 | packageJSON: pkg, 70 | filePath: input, 71 | disableRunning: disableRunning, 72 | }); 73 | const passed = results.filter((result) => { 74 | return result.status === "fulfilled"; 75 | }); 76 | const rejected = results.filter((result) => { 77 | return result.status === "rejected"; 78 | }); 79 | const errors = rejected.map((result) => { 80 | const error = (result as any).reason; 81 | const filePathLineColumn = `${error.fileName}:${error.lineNumber}:${error.columnNumber}`; 82 | return `Failed at ${filePathLineColumn} 83 | 84 | ${error.message} 85 | ---------- 86 | ${result.code} 87 | ---------- 88 | `; 89 | }); 90 | const message = `# Test Results 91 | Pass: ${passed.length} 92 | Fail: ${rejected.length} 93 | Total: ${passed.length + rejected.length} 94 | ${ 95 | errors.length > 0 96 | ? `Errors: 97 | ${errors.join("\n")}` 98 | : "" 99 | }`; 100 | if (rejected.length > 0) { 101 | throw new Error(message); 102 | } 103 | return message; 104 | } 105 | -------------------------------------------------------------------------------- /packages/power-doctest/src/power-doctest.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import * as path from "path"; 3 | import { test } from "@power-doctest/tester"; 4 | import { parse as parseJavaScript } from "@power-doctest/javascript"; 5 | import { parse as parseMarkdown } from "@power-doctest/markdown"; 6 | import { parse as parseAsciidoctor } from "@power-doctest/asciidoctor"; 7 | const allSettled = require("promise.allsettled"); 8 | 9 | export interface RunPowerDoctestOption { 10 | contentType: "javascript" | "markdown" | "asciidoctor"; 11 | content: string; 12 | filePath: string; 13 | packageDir: string; 14 | packageJSON?: {}; 15 | disableRunning: boolean; 16 | } 17 | 18 | export const createMockRequire = (packageDir: string, pkg?: any) => { 19 | if (!pkg) { 20 | return {}; 21 | } 22 | const name = pkg["name"]; 23 | const main = pkg["main"]; 24 | if (!pkg["main"] || !name) { 25 | return {}; 26 | } 27 | const mainFilepath = path.join(packageDir, main); 28 | if (!fs.existsSync(mainFilepath)) { 29 | throw new Error("Not found main file. " + mainFilepath); 30 | } 31 | if (!name) { 32 | throw new Error("Not defined pkg.name" + pkg); 33 | } 34 | return { 35 | [name]: require(mainFilepath), 36 | }; 37 | }; 38 | 39 | export async function runPowerDoctest( 40 | options: RunPowerDoctestOption 41 | ): Promise<{ status: "fulfilled" | "rejected"; code: string; value?: any; reason?: Error }[]> { 42 | const requireMock = createMockRequire(options.packageDir, options.packageJSON); 43 | const results = (() => { 44 | if (options.contentType === "javascript") { 45 | return parseJavaScript({ 46 | content: options.content, 47 | filePath: options.filePath, 48 | }); 49 | } 50 | if (options.contentType === "markdown") { 51 | return parseMarkdown({ 52 | content: options.content, 53 | filePath: options.filePath, 54 | }); 55 | } 56 | if (options.contentType === "asciidoctor") { 57 | return parseAsciidoctor({ 58 | content: options.content, 59 | filePath: options.filePath, 60 | }); 61 | } 62 | return []; 63 | })(); 64 | const promises = results.map((result) => { 65 | return test( 66 | { 67 | ...result, 68 | doctestOptions: { 69 | ...result.doctestOptions, 70 | requireMock, 71 | }, 72 | }, 73 | { 74 | disableRunning: options.disableRunning, 75 | } 76 | ); 77 | }); 78 | const settledResults = await allSettled(promises); 79 | return settledResults.map((testResult: any, index: number) => { 80 | if (testResult.status === "fulfilled") { 81 | return { 82 | status: testResult.status, 83 | value: testResult.value, 84 | code: results[index].code, 85 | }; 86 | } else { 87 | return { 88 | status: testResult.status, 89 | reason: testResult.reason as Error, 90 | code: results[index].code, 91 | }; 92 | } 93 | }); 94 | } 95 | -------------------------------------------------------------------------------- /packages/power-doctest/test/fixture-pkg/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "test-module", 3 | }; 4 | -------------------------------------------------------------------------------- /packages/power-doctest/test/fixture-pkg/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-module", 3 | "main": "index.js" 4 | } 5 | -------------------------------------------------------------------------------- /packages/power-doctest/test/power-doctest.test.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | import { runPowerDoctest } from "../src/power-doctest"; 3 | import * as assert from "assert"; 4 | 5 | describe("runPowerDoctest", function () { 6 | it("should test", () => { 7 | return runPowerDoctest({ 8 | content: ` 9 | const { name } = require("test-module"); 10 | console.log(name); // => "test-module" 11 | `, 12 | contentType: "javascript", 13 | filePath: "./test.js", 14 | packageDir: path.join(__dirname, "fixture-pkg"), 15 | packageJSON: require(path.join(__dirname, "fixture-pkg", "package.json")), 16 | disableRunning: false, 17 | }).then((results) => { 18 | assert.strictEqual(results.length, 1); 19 | assert.strictEqual(results[0].status, "fulfilled"); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/power-doctest/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "noEmit": true 6 | }, 7 | "include": [ 8 | "../src/**/*", 9 | "./**/*" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/power-doctest/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "esModuleInterop": true, 7 | "newLine": "LF", 8 | "outDir": "./lib/", 9 | "target": "es5", 10 | "sourceMap": true, 11 | "declaration": true, 12 | "jsx": "preserve", 13 | "lib": [ 14 | "esnext", 15 | "dom" 16 | ], 17 | /* Strict Type-Checking Options */ 18 | "strict": true, 19 | "skipLibCheck": true, 20 | /* Additional Checks */ 21 | /* Report errors on unused locals. */ 22 | "noUnusedLocals": true, 23 | /* Report errors on unused parameters. */ 24 | "noUnusedParameters": true, 25 | /* Report error when not all code paths in function return a value. */ 26 | "noImplicitReturns": true, 27 | /* Report errors for fallthrough cases in switch statement. */ 28 | "noFallthroughCasesInSwitch": true 29 | }, 30 | "include": [ 31 | "src/**/*" 32 | ], 33 | "exclude": [ 34 | ".git", 35 | "node_modules" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "packages/*" 3 | - "packages/@power-doctest/*" 4 | --------------------------------------------------------------------------------