├── .editorconfig ├── .gitattributes ├── .github ├── FUNDING.yml └── workflows │ ├── codeql-analysis.yml │ ├── documentation.yml │ ├── quality.yml │ └── release.yml ├── .gitignore ├── .husky ├── .npmignore ├── commit-msg └── pre-commit ├── .jest ├── __mocks__ │ └── PdfExtractor.ts └── jest.setup.ts ├── .madgerc ├── .npmignore ├── .yarnrc ├── LICENSE ├── README.md ├── android ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ ├── main │ ├── AndroidManifest.xml │ └── kotlin │ │ └── com │ │ └── reactnative │ │ └── pdf │ │ └── extractor │ │ ├── PdfExtractorModule.kt │ │ ├── PdfExtractorPackage.kt │ │ └── core │ │ ├── PdfHandler.kt │ │ └── StringHandler.kt │ └── test │ └── kotlin │ └── com │ └── reactnative │ └── pdf │ └── extractor │ └── unit │ ├── PdfHandlerTest.kt │ ├── StringHandlerTest.kt │ └── utils │ ├── TestUtils.kt │ ├── mocks │ ├── AndroidLogMock.kt │ ├── ContentResolverMock.kt │ ├── InputStreamMock.kt │ ├── PDDocumentMock.kt │ ├── PDFBoxResourceLoaderMock.kt │ ├── PDFTextStripperMock.kt │ ├── UriMock.kt │ └── interfaces │ │ └── Mock.kt │ └── resources │ ├── multiline-formatted.txt │ └── multiline-unformatted.txt ├── babel.config.js ├── index.ts ├── jest.config.ts ├── package.json ├── sample ├── android │ ├── app │ │ ├── build.gradle │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── assets │ │ │ └── index.android.bundle │ │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── reactnativepdfextractor │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ │ └── xml │ │ │ └── provider_paths.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── app.json ├── babel.config.js ├── index.tsx ├── metro.config.js ├── package.json ├── src │ └── App.tsx └── yarn.lock ├── scripts └── bootstrap.js ├── sonar-project.properties ├── src ├── chains │ ├── __tests__ │ │ ├── Chain.spec.ts │ │ └── ChainLink.spec.ts │ ├── core │ │ ├── AbstractHandler.ts │ │ ├── Chain.ts │ │ └── ChainLink.ts │ └── index.ts ├── extractors │ ├── __tests__ │ │ ├── Base.spec.ts │ │ └── Common.spec.ts │ ├── core │ │ ├── Base.ts │ │ ├── Common.ts │ │ ├── Extractor.tsx │ │ └── Styles.ts │ └── index.ts ├── patterns │ ├── __tests__ │ │ └── Patterns.test.ts │ └── index.ts ├── types │ └── index.ts └── utils │ ├── __tests__ │ └── Utils.spec.ts │ └── index.ts ├── tsconfig.json ├── website ├── .gitignore ├── README.md ├── babel.config.js ├── docs │ ├── api │ │ ├── _category_.json │ │ ├── extractors │ │ │ ├── BaseExtractor.md │ │ │ ├── Extractor.md │ │ │ └── _category_.json │ │ └── patterns.md │ ├── before-you-start.md │ ├── code-of-conduct.md │ ├── contributing.md │ ├── getting-started │ │ ├── _category_.json │ │ ├── configuration.md │ │ ├── installation.md │ │ ├── playground.md │ │ └── usage.md │ └── license.md ├── docusaurus.config.js ├── package.json ├── sidebars.js ├── src │ ├── components │ │ └── HomepageFeatures │ │ │ ├── index.tsx │ │ │ └── styles.module.css │ ├── css │ │ └── custom.css │ └── pages │ │ ├── index.module.css │ │ └── index.tsx ├── static │ ├── .nojekyll │ └── img │ │ ├── docusaurus.png │ │ ├── favicon.ico │ │ ├── react-native-pdf-extractor.svg │ │ ├── sample.png │ │ ├── undraw_docusaurus_mountain.svg │ │ ├── undraw_docusaurus_react.svg │ │ └── undraw_docusaurus_tree.svg ├── tsconfig.json └── yarn.lock └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | indent_style = space 10 | indent_size = 2 11 | 12 | end_of_line = lf 13 | charset = utf-8 14 | trim_trailing_whitespace = true 15 | insert_final_newline = true 16 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | # specific for windows script files 3 | *.bat text eol=crlf -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [1fabiopereira]# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "main" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "main" ] 20 | schedule: 21 | - cron: '21 4 * * 2' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript', 'TypeScript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | -------------------------------------------------------------------------------- /.github/workflows/documentation.yml: -------------------------------------------------------------------------------- 1 | name: Generate Documentation 2 | 3 | on: 4 | pull_request: 5 | branches: [main] 6 | push: 7 | branches: [main] 8 | 9 | jobs: 10 | checks: 11 | if: github.event_name != 'push' 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Git checkout 16 | uses: actions/checkout@v2 17 | 18 | - name: Use Node.js Version 16.x 19 | uses: actions/setup-node@v2 20 | with: 21 | node-version: 16.14.x 22 | 23 | - name: Test Build 24 | run: | 25 | cd website/ 26 | npm i 27 | npm run build 28 | 29 | gh-release: 30 | if: github.event_name != 'pull_request' 31 | runs-on: ubuntu-latest 32 | 33 | steps: 34 | - name: Git checkout 35 | uses: actions/checkout@v2 36 | 37 | - name: 'Use Node.js Version 16.x' 38 | uses: actions/setup-node@v2 39 | with: 40 | node-version: 16.14.x 41 | 42 | - name: Add key to allow access to repository 43 | env: 44 | SSH_AUTH_SOCK: /tmp/ssh_agent.sock 45 | run: | 46 | mkdir -p ~/.ssh 47 | ssh-keyscan github.com >> ~/.ssh/known_hosts 48 | echo "${{ secrets.GH_PAGES_DEPLOY }}" > ~/.ssh/id_rsa 49 | chmod 600 ~/.ssh/id_rsa 50 | cat <> ~/.ssh/config 51 | Host github.com 52 | HostName github.com 53 | IdentityFile ~/.ssh/id_rsa 54 | EOT 55 | 56 | - name: Release to GitHub Pages 57 | env: 58 | USE_SSH: true 59 | GIT_USER: git 60 | run: | 61 | git config --global user.email ${{ secrets.EMAIL }} 62 | git config --global user.name ${{ secrets.USERNAME }} 63 | cd website/ 64 | npm i 65 | npm run build 66 | npx docusaurus deploy -------------------------------------------------------------------------------- /.github/workflows/quality.yml: -------------------------------------------------------------------------------- 1 | name: Check Code Quality 2 | 3 | on: 4 | push: 5 | branches: [ main, develop ] 6 | pull_request: 7 | branches: [ main, develop ] 8 | 9 | jobs: 10 | lint-and-tests: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Git checkout 15 | uses: actions/checkout@v2 16 | with: 17 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis 18 | 19 | - name: Use Node.js Version 16.x 20 | uses: actions/setup-node@v2 21 | with: 22 | node-version: 16.14.x 23 | 24 | - name: Use JDK Version 11 25 | uses: actions/setup-java@v3 26 | with: 27 | distribution: 'temurin' 28 | java-version: '11' 29 | 30 | - name: Install dependencies 31 | run: yarn install --frozen-lockfile 32 | 33 | - name: Type check 34 | run: yarn type-check 35 | 36 | - name: Lint 37 | run: yarn lint 38 | 39 | - name: Check circular dependencies 40 | run: yarn circular 41 | 42 | - name: Run Jest Unit Tests 43 | run: yarn test 44 | 45 | - name: Typescript build 46 | run: yarn build 47 | 48 | - name: SonarCloud Scan Typescript 49 | run: yarn sonar 50 | env: 51 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 52 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 53 | 54 | - name: Build Gradle and analyze 55 | run: yarn build 56 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release NPM package 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | deploy-package: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | # Checkout the exact commit tagged on the release. 13 | - name: Checkout repo 14 | uses: actions/checkout@v2 15 | with: 16 | ref: ${{ github.event.release.target_commitish }} 17 | 18 | # This is the action in this repo! 👇 19 | # Note we set an `id` called `release`. We'll use that later... 20 | - name: Validate and extract release information 21 | id: release 22 | uses: manovotny/github-releases-for-automated-package-publishing-action@v1.0.0 23 | 24 | # When setting the node version for publishing a release, it's also impotant 25 | # to set `always-auth` and `registry-url` too. I've encountered vauge errors 26 | # and publishing doesn't work unless they are supplied. 27 | # 28 | # This example is using NPM's registry. If you were publishing to GitHub's 29 | # Package registry, you'd use `https://npm.pkg.github.com` instead. 30 | - name: Use Node.js Version 16.x 31 | uses: actions/setup-node@v2 32 | with: 33 | always-auth: true 34 | node-version: 16.14.x 35 | registry-url: 'https://registry.npmjs.org' 36 | 37 | - name: Use JDK Version 11 38 | uses: actions/setup-java@v3 39 | with: 40 | distribution: 'temurin' 41 | java-version: '11' 42 | 43 | # Perform installs dependencies 44 | - name: Install dependencies 45 | run: yarn install --frozen-lockfile 46 | 47 | # Perform type check 48 | - name: Type check 49 | run: yarn type-check 50 | 51 | # Perform lint 52 | - name: Lint 53 | run: yarn lint 54 | 55 | # Perform check for circular dependencies 56 | - name: Check circular dependencies 57 | run: yarn circular 58 | 59 | # Run Jest Unit Tests 60 | - name: Run Jest Unit Tests 61 | run: yarn test 62 | 63 | # Run Gradle unit Tests 64 | - name: Run Gradle Unit Tests 65 | run: | 66 | cd android/ 67 | ./gradlew testDebugUnitTest --console verbose 68 | 69 | # Perform build project 70 | - name: Build 71 | run: yarn build 72 | 73 | # The last two steps will publish the package. Note that we're using 74 | # information from the `release` step above (I told you we'd use it 75 | # later). Notice the `if` statements on both steps... 76 | # 77 | # If there *is* a tag (ie. `beta`, `canary`, etc.), we publish a 78 | # "pre-release" or "tagged" version of a package (ie. 1.2.3-beta.1). 79 | # 80 | # If there *is not* a tag (ie. `beta`, `canary`, etc.), we publish a 81 | # version of a package (ie. 1.2.3). 82 | # 83 | # This example is using yarn to publish, but you could just as easily 84 | # use npm, if you prefer. It's also publishing to the NPM registry, 85 | # thus, it's using `NPM_TOKEN`, but you could just as easily use 86 | # `GITHUB_TOKEN` if you were publishing to the GitHub Package registry. 87 | 88 | # This will publish a "pre-release" or "tagged" version of a package. 89 | - name: Publish tagged version 90 | if: steps.release.outputs.tag != '' 91 | run: yarn publish --new-version ${{ steps.release.outputs.version }} --tag ${{ steps.release.outputs.tag }} 92 | env: 93 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 94 | 95 | # This will publish a version of a package. 96 | - name: Publish version 97 | if: steps.release.outputs.tag == '' 98 | run: yarn publish --new-version ${{ steps.release.outputs.version }} 99 | env: 100 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 101 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | .history/ 5 | 6 | # XDE 7 | .expo/ 8 | 9 | # VSCode 10 | .vscode/ 11 | jsconfig.json 12 | 13 | ############ 14 | # Node 15 | ############ 16 | # Logs 17 | logs 18 | *.log 19 | npm-debug.log* 20 | 21 | # Runtime data 22 | pids 23 | *.pid 24 | *.seed 25 | 26 | # Directory for instrumented libs generated by jscoverage/JSCover 27 | lib-cov 28 | 29 | # Coverage directory used by tools like istanbul 30 | coverage 31 | 32 | # nyc test coverage 33 | .nyc_output 34 | 35 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 36 | .grunt 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (http://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | node_modules 46 | jspm_packages 47 | 48 | # Optional npm cache directory 49 | .npm 50 | 51 | # Optional REPL history 52 | .node_repl_history 53 | 54 | ################ 55 | # JetBrains 56 | ################ 57 | .idea 58 | 59 | ## File-based project format: 60 | *.iws 61 | 62 | ## Plugin-specific files: 63 | 64 | # IntelliJ 65 | /out/ 66 | 67 | # mpeltonen/sbt-idea plugin 68 | .idea_modules/ 69 | 70 | # JIRA plugin 71 | atlassian-ide-plugin.xml 72 | 73 | # Crashlytics plugin (for Android Studio and IntelliJ) 74 | com_crashlytics_export_strings.xml 75 | crashlytics.properties 76 | crashlytics-build.properties 77 | fabric.properties 78 | 79 | 80 | ############ 81 | # iOS 82 | ############ 83 | # Xcode 84 | # 85 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 86 | 87 | ## Build generated 88 | ios/build/ 89 | ios/DerivedData/ 90 | 91 | ## Various settings 92 | *.pbxuser 93 | !default.pbxuser 94 | *.mode1v3 95 | !default.mode1v3 96 | *.mode2v3 97 | !default.mode2v3 98 | *.perspectivev3 99 | !default.perspectivev3 100 | ios/xcuserdata/ 101 | 102 | ## Other 103 | *.moved-aside 104 | *.xcuserstate 105 | 106 | ## Obj-C/Swift specific 107 | *.hmap 108 | *.ipa 109 | *.dSYM.zip 110 | *.dSYM 111 | 112 | # CocoaPods 113 | # 114 | # We recommend against adding the Pods directory to your .gitignore. However 115 | # you should judge for yourself, the pros and cons are mentioned at: 116 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 117 | # 118 | ios/Pods/ 119 | 120 | # Carthage 121 | # 122 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 123 | # Carthage/Checkouts 124 | 125 | Carthage/Build 126 | 127 | # fastlane 128 | # 129 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 130 | # screenshots whenever they are needed. 131 | # For more information about the recommended setup visit: 132 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 133 | 134 | fastlane/report.xml 135 | fastlane/screenshots 136 | 137 | 138 | ############ 139 | # Android 140 | ############ 141 | # Built application files 142 | *.apk 143 | *.ap_ 144 | 145 | # Files for the Dalvik VM 146 | *.dex 147 | 148 | # Java class files 149 | *.class 150 | 151 | # Generated files 152 | android/bin/ 153 | android/gen/ 154 | android/out/ 155 | 156 | # Gradle files 157 | android/.gradle/ 158 | android/build/ 159 | 160 | # Local configuration file (sdk path, etc) 161 | local.properties 162 | 163 | # Proguard folder generated by Eclipse 164 | android/proguard/ 165 | 166 | # Log Files 167 | *.log 168 | 169 | # Android Studio Navigation editor temp files 170 | android/.navigation/ 171 | 172 | # Android Studio captures folder 173 | android/captures/ 174 | 175 | # Intellij 176 | *.iml 177 | 178 | # Keystore files 179 | *.jks 180 | 181 | ################## 182 | # React-Native 183 | ################## 184 | # OSX 185 | # 186 | .DS_Store 187 | 188 | # Xcode 189 | # 190 | build/ 191 | *.pbxuser 192 | !default.pbxuser 193 | *.mode1v3 194 | !default.mode1v3 195 | *.mode2v3 196 | !default.mode2v3 197 | *.perspectivev3 198 | !default.perspectivev3 199 | xcuserdata 200 | *.xccheckout 201 | *.moved-aside 202 | DerivedData 203 | *.hmap 204 | *.ipa 205 | *.xcuserstate 206 | project.xcworkspace 207 | 208 | # Android/IJ 209 | # 210 | .idea 211 | .gradle 212 | local.properties 213 | 214 | # node.js 215 | # 216 | node_modules/ 217 | npm-debug.log 218 | 219 | # BUCK 220 | buck-out/ 221 | \.buckd/ 222 | 223 | # Android/IJ 224 | # 225 | .classpath 226 | .cxx 227 | .gradle 228 | .idea 229 | .project 230 | .settings 231 | *.hprof 232 | android.iml 233 | local.properties 234 | 235 | # Ruby / CocoaPods 236 | /ios/Pods/ 237 | /vendor/bundle/ 238 | /example/ios/Pods 239 | /example/vendor/bundle/ 240 | 241 | # node.js 242 | # 243 | node_modules/ 244 | npm-debug.log 245 | yarn-debug.log 246 | yarn-error.log 247 | 248 | # BUCK 249 | buck-out/ 250 | \.buckd/ 251 | android/app/libs 252 | android/keystores/debug.keystore 253 | 254 | # Expo 255 | .expo/* 256 | 257 | # generated by bob 258 | lib/ 259 | 260 | # generated by jest 261 | coverage/ 262 | 263 | # Production 264 | /build 265 | 266 | # Generated files 267 | .docusaurus 268 | .cache-loader 269 | 270 | # Misc 271 | .DS_Store 272 | .env.local 273 | .env.development.local 274 | .env.test.local 275 | .env.production.local 276 | 277 | npm-debug.log* 278 | yarn-debug.log* 279 | yarn-error.log* 280 | 281 | -------------------------------------------------------------------------------- /.husky/.npmignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn commitlint -E HUSKY_GIT_PARAMS 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn lint && yarn typescript 5 | -------------------------------------------------------------------------------- /.jest/__mocks__/PdfExtractor.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | canIExtract: jest.fn(), 3 | getNumberOfPages: jest.fn(), 4 | getText: jest.fn(), 5 | getUri: jest.fn(), 6 | isEncrypted: jest.fn(), 7 | setUri: jest.fn(), 8 | } -------------------------------------------------------------------------------- /.jest/jest.setup.ts: -------------------------------------------------------------------------------- 1 | import PdfExtractor from './__mocks__/PdfExtractor' 2 | 3 | // all native modules 4 | const mocks = { 5 | PdfExtractor, 6 | } 7 | 8 | Object.keys(mocks).forEach((module => jest.doMock(module, () => mocks[module], { virtual: true }))) 9 | 10 | jest.mock('react-native', () => ({ 11 | Platform: { 12 | OS: 'android', 13 | select: jest.fn((data: { android: any, ios: any }) => data.android) 14 | }, 15 | NativeModules: mocks 16 | })) -------------------------------------------------------------------------------- /.madgerc: -------------------------------------------------------------------------------- 1 | { 2 | "fontSize": "10px", 3 | "graphVizOptions": { 4 | "G": { 5 | "rankdir": "LR" 6 | } 7 | }, 8 | "tsConfig": "./tsconfig.json" 9 | } -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # root 2 | .github/ 3 | .husky/ 4 | coverage/ 5 | sample/ 6 | scripts/ 7 | 8 | # lib 9 | lib/typescript/sample/ 10 | lib/typescript/src/__tests__/ 11 | 12 | # android 13 | android/.gradle/ 14 | android/.idea/ 15 | android/build/ 16 | android/local.properties 17 | 18 | # docs 19 | website/ -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | # Override Yarn command so we can automatically setup the repo on running `yarn` 2 | yarn-path "scripts/bootstrap.js" 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Fábio Pereira 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | React Native PDF Extractor Logo
4 | React Native PDF Extractor 5 |

6 | 7 | 8 |

9 | 10 | NPM downloads 11 | 12 | 13 | NPM version 14 | 15 | 16 | 17 | Sonar Cloud 18 | 19 | Package License 20 | 21 |

22 | 23 | This library allows you to extract pdfs file data using matches specifics patterns. 24 | 25 | ## [Documentation](https://1fabiopereira.github.io/react-native-pdf-extractor/) 26 | 27 | - ### [Getting Started](https://1fabiopereira.github.io/react-native-pdf-extractor/docs/before-you-start) 28 | - [Before you start](https://1fabiopereira.github.io/react-native-pdf-extractor/docs/before-you-start) 29 | - [Installation](https://1fabiopereira.github.io/react-native-pdf-extractor/docs/getting-started/installation) 30 | - [Configuration](https://1fabiopereira.github.io/react-native-pdf-extractor/docs/getting-started/configuration) 31 | - [Usage](https://1fabiopereira.github.io/react-native-pdf-extractor/docs/getting-started/usage) 32 | - [Playground app](https://1fabiopereira.github.io/react-native-pdf-extractor/docs/getting-started/playground) 33 | - ### [API](https://1fabiopereira.github.io/react-native-pdf-extractor/docs/api) 34 | 35 | - [Extractors](https://1fabiopereira.github.io/react-native-pdf-extractor/docs/api/extractors) 36 | - [Patterns](https://1fabiopereira.github.io/react-native-pdf-extractor/docs/api/patterns) 37 | 38 | - ### [Code of Conduct](https://1fabiopereira.github.io/react-native-pdf-extractor/docs/code-of-conduct) 39 | - ### [Contributing](https://1fabiopereira.github.io/react-native-pdf-extractor/docs/contributing) 40 | - ### [License](https://1fabiopereira.github.io/react-native-pdf-extractor/docs/license) 41 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | def kotlin_version = rootProject.ext.has('kotlinVersion') 3 | ? rootProject.ext.get('kotlinVersion') 4 | : project.properties['PdfExtractor_kotlinVersion'] 5 | 6 | repositories { 7 | google() 8 | mavenCentral() 9 | maven { url 'https://plugins.gradle.org/m2/' } 10 | } 11 | 12 | dependencies { 13 | classpath('com.android.tools.build:gradle:7+') 14 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 15 | } 16 | } 17 | 18 | apply plugin: 'com.android.library' 19 | apply plugin: 'kotlin-android' 20 | 21 | def kotlin_version = getExtOrDefault("kotlinVersion") 22 | 23 | def getExtOrDefault(name) { 24 | return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['PdfExtractor_' + name] 25 | } 26 | 27 | def getExtOrIntegerDefault(name) { 28 | return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['PdfExtractor_' + name]).toInteger() 29 | } 30 | 31 | android { 32 | compileSdkVersion getExtOrIntegerDefault('compileSdkVersion') 33 | 34 | defaultConfig { 35 | minSdkVersion getExtOrIntegerDefault('minSdkVersion') 36 | targetSdkVersion getExtOrIntegerDefault('targetSdkVersion') 37 | versionCode 1 38 | versionName "0.2.6" 39 | } 40 | 41 | buildTypes { 42 | release { 43 | minifyEnabled true 44 | } 45 | 46 | debug { 47 | minifyEnabled false 48 | testCoverageEnabled true 49 | } 50 | } 51 | 52 | lintOptions { 53 | disable 'GradleCompatible' 54 | } 55 | } 56 | 57 | repositories { 58 | mavenCentral() 59 | google() 60 | 61 | def found = false 62 | def defaultDir = null 63 | def androidSourcesName = 'React Native sources' 64 | 65 | if (rootProject.ext.has('reactNativeAndroidRoot')) { 66 | defaultDir = rootProject.ext.get('reactNativeAndroidRoot') 67 | } else { 68 | defaultDir = new File(projectDir, '/../../../node_modules/react-native/android') 69 | } 70 | 71 | if (defaultDir.exists()) { 72 | maven { 73 | url defaultDir.toString() 74 | name androidSourcesName 75 | } 76 | 77 | logger.info(":${project.name}:reactNativeAndroidRoot ${defaultDir.canonicalPath}") 78 | found = true 79 | } else { 80 | def parentDir = rootProject.projectDir 81 | 82 | 1.upto(5, { 83 | if (found) return true 84 | parentDir = parentDir.parentFile 85 | 86 | def androidSourcesDir = new File(parentDir, 'node_modules/react-native') 87 | def androidPrebuiltBinaryDir = new File(parentDir, 'node_modules/react-native/android') 88 | 89 | if (androidPrebuiltBinaryDir.exists()) { 90 | maven { 91 | url androidPrebuiltBinaryDir.toString() 92 | name androidSourcesName 93 | } 94 | 95 | logger.info(":${project.name}:reactNativeAndroidRoot ${androidPrebuiltBinaryDir.canonicalPath}") 96 | found = true 97 | } else if (androidSourcesDir.exists()) { 98 | maven { 99 | url androidSourcesDir.toString() 100 | name androidSourcesName 101 | } 102 | 103 | logger.info(":${project.name}:reactNativeAndroidRoot ${androidSourcesDir.canonicalPath}") 104 | found = true 105 | } 106 | }) 107 | } 108 | 109 | if (!found) { 110 | throw new GradleException( 111 | "${project.name}: unable to locate React Native android sources. " + 112 | "Ensure you have you installed React Native as a dependency in your project and try again." 113 | ) 114 | } 115 | } 116 | 117 | dependencies { 118 | // noinspection GradleDynamicVersion 119 | api("com.facebook.react:react-native:+") 120 | 121 | // Project dependencies 122 | implementation('com.tom-roush:pdfbox-android:2.0.23.0') 123 | implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version") 124 | 125 | 126 | // Unit Tests dependencies 127 | testImplementation("junit:junit:4.13.2") 128 | testImplementation("pl.pragmatists:JUnitParams:1.1.1") 129 | testImplementation("io.mockk:mockk:1.12.4") 130 | } 131 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.enableJetifier=true 21 | android.useAndroidX=true 22 | 23 | PdfExtractor_compileSdkVersion=33 24 | PdfExtractor_kotlinVersion=1.7.10 25 | PdfExtractor_minSdkVersion=21 26 | PdfExtractor_targetSdkVersion=33 27 | 28 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pdf-extractor/2a5bc1301a287438a20a3b74e8a2caa0e905b2d0/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/reactnative/pdf/extractor/PdfExtractorModule.kt: -------------------------------------------------------------------------------- 1 | package com.reactnative.pdf.extractor 2 | 3 | import android.content.ContentResolver 4 | import android.net.Uri 5 | import androidx.core.content.FileProvider 6 | 7 | import com.facebook.react.bridge.* 8 | import com.reactnative.pdf.extractor.core.PdfHandler 9 | import com.tom_roush.pdfbox.android.PDFBoxResourceLoader 10 | 11 | class PdfExtractorModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { 12 | var path: Uri? = null 13 | 14 | init { 15 | PDFBoxResourceLoader.init(reactContext) 16 | } 17 | 18 | override fun getName(): String { 19 | return "PdfExtractor" 20 | } 21 | 22 | fun getCurrentUri(): Uri? { 23 | try { 24 | return if (path !== null) path else currentActivity?.intent?.data 25 | } catch (e: Exception) { 26 | e.printStackTrace() 27 | return null 28 | } 29 | } 30 | 31 | private fun getCurrentResolver(): ContentResolver? { 32 | try { 33 | return currentActivity?.contentResolver 34 | } catch (e: Exception) { 35 | e.printStackTrace() 36 | return null 37 | } 38 | } 39 | 40 | @ReactMethod 41 | fun getUri(promise: Promise) { 42 | try { 43 | val uri = getCurrentUri() 44 | val path = if(uri !== null) uri.toString() else null 45 | 46 | return promise.resolve(path) 47 | } catch (e:Exception) { 48 | e.printStackTrace() 49 | return promise.resolve(null) 50 | } 51 | } 52 | 53 | @ReactMethod 54 | fun setUri(uri: String, promise: Promise) { 55 | try { 56 | path = Uri.parse(uri) 57 | return promise.resolve(path.toString()) 58 | } catch (e: Exception) { 59 | e.printStackTrace() 60 | return promise.reject(e) 61 | } 62 | } 63 | 64 | @ReactMethod 65 | fun canIExtract(promise: Promise): Any { 66 | try { 67 | val uri = getCurrentUri() 68 | val resolver = getCurrentResolver() 69 | 70 | if (uri !== null && resolver !== null) { 71 | return promise.resolve(resolver.getType(uri).equals("application/pdf")) 72 | } 73 | 74 | return promise.resolve(false) 75 | } catch (e: Exception) { 76 | e.printStackTrace() 77 | return promise.reject(e) 78 | } 79 | } 80 | 81 | @ReactMethod 82 | fun getText(password: String?, promise: Promise) { 83 | try { 84 | val uri = getCurrentUri() 85 | val resolver = getCurrentResolver() 86 | 87 | val data = PdfHandler.getText(uri, resolver, password) 88 | return promise.resolve(data) 89 | } catch (e: Exception) { 90 | e.printStackTrace() 91 | return promise.reject(e) 92 | } 93 | } 94 | 95 | @ReactMethod 96 | fun isEncrypted(promise: Promise) { 97 | try { 98 | val uri = getCurrentUri() 99 | val resolver = getCurrentResolver() 100 | 101 | val data = PdfHandler.isEncrypted(uri, resolver) 102 | return promise.resolve(data) 103 | } catch (e: Exception) { 104 | e.printStackTrace() 105 | return promise.reject(e) 106 | } 107 | } 108 | 109 | @ReactMethod 110 | fun getNumberOfPages(password: String?, promise: Promise) { 111 | try { 112 | val uri = getCurrentUri() 113 | val resolver = getCurrentResolver() 114 | 115 | val data = PdfHandler.getNumberOfPages(uri, resolver, password) 116 | return promise.resolve(data) 117 | } catch (e: Exception) { 118 | e.printStackTrace() 119 | return promise.reject(e) 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/reactnative/pdf/extractor/PdfExtractorPackage.kt: -------------------------------------------------------------------------------- 1 | package com.reactnative.pdf.extractor 2 | 3 | import com.facebook.react.ReactPackage 4 | import com.facebook.react.bridge.NativeModule 5 | import com.facebook.react.bridge.ReactApplicationContext 6 | import com.facebook.react.uimanager.ViewManager 7 | 8 | class PdfExtractorPackage : ReactPackage { 9 | override fun createNativeModules(reactContext: ReactApplicationContext): List { 10 | return listOf(PdfExtractorModule(reactContext)) 11 | } 12 | 13 | override fun createViewManagers(reactContext: ReactApplicationContext): List> { 14 | return emptyList() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/reactnative/pdf/extractor/core/PdfHandler.kt: -------------------------------------------------------------------------------- 1 | package com.reactnative.pdf.extractor.core 2 | 3 | import android.content.ContentResolver 4 | import android.net.Uri 5 | import com.tom_roush.pdfbox.pdmodel.PDDocument 6 | import com.tom_roush.pdfbox.text.PDFTextStripper 7 | import java.io.InputStream 8 | 9 | open class PdfHandler { 10 | companion object { 11 | @JvmStatic 12 | fun isEncrypted(uri: Uri?, resolver: ContentResolver?): Boolean { 13 | val stream = openInputStreamFile(uri, resolver) 14 | 15 | // Check input stream 16 | if (stream === null) throw Exception("File not found.") 17 | 18 | // Try open file and get if is encrypted 19 | return try { 20 | val document = PDDocument.load(stream) 21 | val pages = document.numberOfPages 22 | 23 | document.close() 24 | stream.close() 25 | 26 | pages <= 0 27 | } catch (e: Exception) { 28 | val regex = Regex("((\\s(decrypt)\\s)|\\s(password)\\s|(incorrect))") 29 | e.message?.let { regex.containsMatchIn(it) } == true 30 | } 31 | } 32 | 33 | @JvmStatic 34 | fun getText(uri: Uri?, resolver: ContentResolver?, password: String?): String? { 35 | val document = load(uri, resolver, password) 36 | val data = extract(document) 37 | document?.close() 38 | 39 | return data 40 | } 41 | 42 | @JvmStatic 43 | fun getNumberOfPages(uri: Uri?, resolver: ContentResolver?, password: String?): Int? { 44 | val document = load(uri, resolver, password) 45 | val pages = document?.numberOfPages 46 | 47 | document?.close() 48 | 49 | return pages 50 | } 51 | 52 | @JvmStatic 53 | fun load(uri: Uri?, resolver: ContentResolver?, password: String?): PDDocument? { 54 | val encrypted = isEncrypted(uri, resolver) 55 | 56 | // Check password is required and was provide 57 | if (encrypted && (password === null || password.isEmpty() || password.isBlank())) { 58 | throw Exception("Password is required.") 59 | } 60 | 61 | val stream = openInputStreamFile(uri, resolver) 62 | 63 | // Apply password if necessary and get PDDocument instance 64 | return if (encrypted) { 65 | PDDocument.load(stream, password) 66 | } else { 67 | PDDocument.load(stream) 68 | } 69 | } 70 | 71 | @JvmStatic 72 | private fun openInputStreamFile(uri: Uri?, resolver: ContentResolver?): InputStream? { 73 | return if (uri !== null && resolver !== null) { 74 | resolver.openInputStream(uri) 75 | } else { 76 | null 77 | } 78 | } 79 | 80 | @JvmStatic 81 | fun extract(document: PDDocument?): String? { 82 | if (document === null) return null 83 | val data = PDFTextStripper().getText(document) 84 | 85 | return StringHandler.format(data) 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/reactnative/pdf/extractor/core/StringHandler.kt: -------------------------------------------------------------------------------- 1 | package com.reactnative.pdf.extractor.core 2 | 3 | class StringHandler { 4 | companion object { 5 | @JvmStatic 6 | fun format(data: String?): String? { 7 | if(data === null) return null 8 | 9 | val lines = data.lines() 10 | 11 | return lines 12 | .map { line -> line.replace("\\s+".toRegex(), " ").trim() } 13 | .filter { line -> line.isNotEmpty() || line.isNotBlank() } 14 | .joinToString("\n") 15 | .replace("(\\n)\$".toRegex(), "") 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /android/src/test/kotlin/com/reactnative/pdf/extractor/unit/PdfHandlerTest.kt: -------------------------------------------------------------------------------- 1 | package com.reactnative.pdf.extractor.unit 2 | 3 | import android.net.Uri 4 | import com.reactnative.pdf.extractor.core.PdfHandler 5 | import com.reactnative.pdf.extractor.core.StringHandler 6 | import com.reactnative.pdf.extractor.unit.utils.TestUtils 7 | import com.reactnative.pdf.extractor.unit.utils.mocks.* 8 | 9 | import io.mockk.* 10 | import junitparams.JUnitParamsRunner 11 | import junitparams.Parameters 12 | 13 | import org.junit.After 14 | import org.junit.Assert 15 | import org.junit.Before 16 | import org.junit.Test 17 | import org.junit.runner.RunWith 18 | import org.junit.runners.Parameterized 19 | import java.io.InputStream 20 | 21 | @RunWith(JUnitParamsRunner::class) 22 | class PdfHandlerTest { 23 | private val uri = UriMock() 24 | private val log = AndroidLogMock() 25 | private val stream = InputStreamMock() 26 | private val loader = PDDocumentMock() 27 | private val resolver = ContentResolverMock() 28 | private val boxResourceLoader = PDFBoxResourceLoaderMock() 29 | 30 | private val localUri = uri.mock() 31 | private val localStream = stream.mock() 32 | 33 | @Before 34 | fun setUp() { 35 | MockKAnnotations.init(this) 36 | log.mock() 37 | boxResourceLoader.mock() 38 | } 39 | 40 | @After 41 | fun destroy() { 42 | clearAllMocks() 43 | } 44 | 45 | // ====================== IS ENCRYPTED ====================== // 46 | 47 | @Parameterized.Parameters 48 | fun isEncryptedWithoutExceptionsCases(): Any { 49 | return listOf( 50 | arrayOf(localUri, localStream, 1, false), // check if PDF file is not encrypted 51 | arrayOf(localUri, localStream, 0, true), // check if PDF file is encrypted 52 | ) 53 | } 54 | 55 | @Parameterized.Parameters 56 | fun isEncryptedWithExceptionsCases(): Any { 57 | val localException = Exception("File not found.") 58 | 59 | return listOf( 60 | arrayOf(localUri, null, 0, localException), // try check if PDF file is encrypted when STREAM was passed null 61 | arrayOf(null, localStream, 0, localException), // try check if PDF file is encrypted when URI was passed null 62 | arrayOf(null, null, 0, localException), // try check if PDF file is encrypted when URI and STREAM was passed null 63 | ) 64 | } 65 | 66 | @Test 67 | @Parameters(method = "isEncryptedWithoutExceptionsCases") 68 | fun isEncryptedWithoutExceptionsCasesTest(uri: Uri?, stream: InputStream?, pages: Int, expected: Boolean) { 69 | loader.update(pages).mock() 70 | val localResolver = resolver.update(stream).mock() 71 | val result = PdfHandler.isEncrypted(uri, localResolver) 72 | 73 | Assert.assertEquals(expected, result) 74 | } 75 | 76 | @Test 77 | @Parameters(method = "isEncryptedWithExceptionsCases") 78 | fun isEncryptedWithExceptionsCasesTest(uri: Uri?, stream: InputStream?, pages: Int, expected: Exception) { 79 | loader.update(pages).mock() 80 | val localResolver = resolver.update(stream).mock() 81 | val exception = Assert.assertThrows(Exception::class.java) { 82 | PdfHandler.isEncrypted(uri, localResolver) 83 | } 84 | 85 | Assert.assertEquals(expected.message, exception.message) 86 | } 87 | 88 | // ====================== LOAD ====================== // 89 | 90 | @Parameterized.Parameters 91 | fun loadWithoutExceptionsCases(): List { 92 | return listOf( 93 | arrayOf(localUri, localStream, null, 1), // try load PDF file when it's not encrypted 94 | arrayOf(localUri, localStream, "password", 0), // try load PDF file when it's encrypted. (password required) 95 | ) 96 | } 97 | 98 | @Parameterized.Parameters 99 | fun loadWithExceptionsCases(): List { 100 | val localException = Exception("Password is required.") 101 | 102 | return listOf( 103 | arrayOf(localUri, localStream, null, localException), // try load PDF file when password is required but was passed null 104 | arrayOf(localUri, localStream, "", localException), // try load PDF file when password is required but was passed empty 105 | arrayOf(localUri, localStream, " ", localException), // try load PDF file when password is required but was passed blank 106 | ) 107 | } 108 | 109 | @Test 110 | @Parameters(method = "loadWithoutExceptionsCases") 111 | fun loadWithoutExceptionsCasesTest(uri: Uri?, stream: InputStream?, password: String?, pages: Int) { 112 | val doc = loader.update(pages).mock().getDoc() 113 | val localResolver = resolver.update(stream).mock() 114 | val result = PdfHandler.load(uri, localResolver, password) 115 | 116 | Assert.assertEquals(doc, result) 117 | } 118 | 119 | @Test 120 | @Parameters(method = "loadWithExceptionsCases") 121 | fun loadWithExceptionsCasesTest(uri: Uri, stream: InputStream, password: String?, expected: Exception) { 122 | loader.update(0).mock() 123 | val localResolver = resolver.update(stream).mock() 124 | val exception = Assert.assertThrows(Exception::class.java) { 125 | PdfHandler.load(uri, localResolver, password) 126 | } 127 | 128 | Assert.assertEquals(expected.message, exception.message) 129 | } 130 | 131 | // ====================== GET NUMBER OF PAGES ====================== // 132 | 133 | @Parameterized.Parameters 134 | fun getNumberOfPagesWithoutExceptionsCases(): Any { 135 | return listOf( 136 | arrayOf(localUri, localStream, null, 1), // try get number of pages from PDF file when it's not encrypted 137 | arrayOf(localUri, localStream, "password", 0), // try get number of pages from PDF file when it's encrypted (password required) 138 | ) 139 | } 140 | 141 | @Test 142 | @Parameters(method = "getNumberOfPagesWithoutExceptionsCases") 143 | fun getNumberOfPagesWithoutExceptionsCasesTest(uri: Uri?, stream: InputStream?, password: String?, pages: Int) { 144 | loader.update(pages).mock() 145 | val localResolver = resolver.update(stream).mock() 146 | val result = PdfHandler.getNumberOfPages(uri, localResolver, password) 147 | 148 | Assert.assertEquals(pages, result) 149 | } 150 | 151 | // ====================== GET TEXT ====================== // 152 | 153 | @Parameterized.Parameters 154 | fun getTextWithoutExceptionsCases(): Any { 155 | val localText = TestUtils.loadText("multiline-unformatted.txt") 156 | 157 | return listOf( 158 | arrayOf(localUri, localStream, null, 1, localText), // try get text from PDF file when it's not encrypted without pattern 159 | arrayOf(localUri, localStream, "password", 0, localText), // try get text from PDF file when it's encrypted without pattern (password required) 160 | ) 161 | } 162 | 163 | @Test 164 | @Parameters(method = "getTextWithoutExceptionsCases") 165 | fun getTextWithoutExceptionsCasesTest(uri: Uri, stream: InputStream, password: String?, pages: Int, text: String) { 166 | loader.update(pages).mock() 167 | PDFTextStripperMock().update(text).mock() 168 | 169 | val localResolver = resolver.update(stream).mock() 170 | val result = PdfHandler.getText(uri, localResolver, password) 171 | 172 | Assert.assertEquals(StringHandler.format(text), result) 173 | } 174 | } 175 | 176 | -------------------------------------------------------------------------------- /android/src/test/kotlin/com/reactnative/pdf/extractor/unit/StringHandlerTest.kt: -------------------------------------------------------------------------------- 1 | package com.reactnative.pdf.extractor.unit 2 | 3 | import com.reactnative.pdf.extractor.core.StringHandler 4 | import com.reactnative.pdf.extractor.unit.utils.TestUtils 5 | import io.mockk.MockKAnnotations 6 | import io.mockk.clearAllMocks 7 | 8 | import junitparams.JUnitParamsRunner 9 | import junitparams.Parameters 10 | import org.junit.After 11 | 12 | import org.junit.Assert 13 | import org.junit.Before 14 | import org.junit.Test 15 | import org.junit.runner.RunWith 16 | import org.junit.runners.Parameterized 17 | 18 | @RunWith(JUnitParamsRunner::class) 19 | class StringHandlerTest { 20 | 21 | @Before 22 | fun setUp() { 23 | MockKAnnotations.init(this) 24 | } 25 | 26 | @After 27 | fun destroy() { 28 | clearAllMocks() 29 | } 30 | 31 | // ====================== FORMAT ====================== // 32 | 33 | @Parameterized.Parameters 34 | fun formatWithoutExceptionsCases(): List> { 35 | val localText = TestUtils.loadText("multiline-unformatted.txt") 36 | val localExpected = TestUtils.removeExtraLine(TestUtils.loadText("multiline-formatted.txt")) 37 | 38 | return listOf( 39 | arrayOf(" \n", ""), 40 | arrayOf(null, null), 41 | arrayOf(localText, localExpected), 42 | ) 43 | } 44 | 45 | @Test 46 | @Parameters(method = "formatWithoutExceptionsCases") 47 | fun formatWithoutExceptionsCasesTest(text: String?, expected: String?) { 48 | val result = StringHandler.format(text) 49 | Assert.assertEquals(expected, result) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /android/src/test/kotlin/com/reactnative/pdf/extractor/unit/utils/TestUtils.kt: -------------------------------------------------------------------------------- 1 | package com.reactnative.pdf.extractor.unit.utils 2 | 3 | import java.io.BufferedReader 4 | import java.io.File 5 | 6 | class TestUtils { 7 | companion object { 8 | private const val resourcesPath = "src/test/kotlin/com/reactnative/pdf/extractor/unit/utils/resources" 9 | 10 | @JvmStatic 11 | fun loadText(filename: String): String { 12 | val bufferedReader: BufferedReader = File("$resourcesPath/${filename}").bufferedReader() 13 | return bufferedReader.use { it.readText() } 14 | } 15 | 16 | @JvmStatic 17 | fun removeExtraLine(str: String): String { 18 | return str.replace("(\\n)$".toRegex(), "") 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /android/src/test/kotlin/com/reactnative/pdf/extractor/unit/utils/mocks/AndroidLogMock.kt: -------------------------------------------------------------------------------- 1 | package com.reactnative.pdf.extractor.unit.utils.mocks 2 | 3 | import com.reactnative.pdf.extractor.unit.utils.mocks.interfaces.Mock 4 | import io.mockk.every 5 | import io.mockk.mockkStatic 6 | 7 | import android.util.Log 8 | 9 | class AndroidLogMock(): Mock { 10 | override fun mock() { 11 | mockkStatic(Log::class) 12 | every { Log.w(any(), any()) } returns Int.MAX_VALUE 13 | every { Log.w(any(), any()) } returns Int.MAX_VALUE 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /android/src/test/kotlin/com/reactnative/pdf/extractor/unit/utils/mocks/ContentResolverMock.kt: -------------------------------------------------------------------------------- 1 | package com.reactnative.pdf.extractor.unit.utils.mocks 2 | 3 | import android.content.ContentResolver 4 | import com.reactnative.pdf.extractor.unit.utils.mocks.interfaces.Mock 5 | 6 | import io.mockk.every 7 | import io.mockk.mockk 8 | import java.io.InputStream 9 | 10 | class ContentResolverMock(): Mock { 11 | private val resolver = mockk(relaxed = true) 12 | private var stream: InputStream? = null 13 | 14 | fun update(input: InputStream?): ContentResolverMock { 15 | stream = input 16 | return this 17 | } 18 | 19 | override fun mock(): ContentResolver { 20 | every { resolver.openInputStream(any()) } returns stream 21 | return resolver 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /android/src/test/kotlin/com/reactnative/pdf/extractor/unit/utils/mocks/InputStreamMock.kt: -------------------------------------------------------------------------------- 1 | package com.reactnative.pdf.extractor.unit.utils.mocks 2 | 3 | import com.reactnative.pdf.extractor.unit.utils.mocks.interfaces.Mock 4 | import io.mockk.mockk 5 | import java.io.InputStream 6 | 7 | class InputStreamMock(): Mock { 8 | private val inputStream = mockk(relaxed = true) 9 | 10 | override fun mock(): InputStream { 11 | return inputStream 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /android/src/test/kotlin/com/reactnative/pdf/extractor/unit/utils/mocks/PDDocumentMock.kt: -------------------------------------------------------------------------------- 1 | package com.reactnative.pdf.extractor.unit.utils.mocks 2 | 3 | import com.reactnative.pdf.extractor.unit.utils.mocks.interfaces.Mock 4 | import com.tom_roush.pdfbox.pdmodel.PDDocument 5 | 6 | import io.mockk.every 7 | import io.mockk.mockk 8 | import io.mockk.mockkStatic 9 | 10 | import java.io.InputStream 11 | 12 | class PDDocumentMock(): Mock { 13 | private var document: PDDocument = mockk(relaxed = true) 14 | private var totalOfPages: Int = 0 15 | 16 | fun update(pages: Int): PDDocumentMock { 17 | totalOfPages = pages 18 | return this 19 | } 20 | 21 | fun getDoc(): PDDocument { 22 | return document 23 | } 24 | 25 | override fun mock(): PDDocumentMock { 26 | mockkStatic(PDDocument::class) 27 | every { PDDocument.load(ofType(InputStream::class)) } returns document 28 | every { PDDocument.load(ofType(InputStream::class), ofType(String::class)) } returns document 29 | every { document.numberOfPages } returns totalOfPages 30 | every { document.close() } returns Unit 31 | 32 | return this 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /android/src/test/kotlin/com/reactnative/pdf/extractor/unit/utils/mocks/PDFBoxResourceLoaderMock.kt: -------------------------------------------------------------------------------- 1 | package com.reactnative.pdf.extractor.unit.utils.mocks 2 | 3 | import android.content.Context 4 | import com.reactnative.pdf.extractor.unit.utils.mocks.interfaces.Mock 5 | import com.tom_roush.pdfbox.android.PDFBoxResourceLoader 6 | import io.mockk.mockk 7 | 8 | class PDFBoxResourceLoaderMock(): Mock { 9 | private val context = mockk(relaxed = true) 10 | 11 | override fun mock() { 12 | PDFBoxResourceLoader.init(context) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /android/src/test/kotlin/com/reactnative/pdf/extractor/unit/utils/mocks/PDFTextStripperMock.kt: -------------------------------------------------------------------------------- 1 | package com.reactnative.pdf.extractor.unit.utils.mocks 2 | 3 | import com.reactnative.pdf.extractor.unit.utils.mocks.interfaces.Mock 4 | import com.tom_roush.pdfbox.pdmodel.PDDocument 5 | import com.tom_roush.pdfbox.text.PDFTextStripper 6 | 7 | import io.mockk.every 8 | import io.mockk.mockk 9 | import io.mockk.mockkConstructor 10 | 11 | class PDFTextStripperMock(): Mock { 12 | private lateinit var text: String 13 | 14 | fun update(incoming: String?): PDFTextStripperMock { 15 | if (incoming != null) text = incoming 16 | return this 17 | } 18 | 19 | override fun mock() { 20 | mockkConstructor(PDFTextStripper::class) 21 | mockk(relaxed = true) 22 | every { anyConstructed() 23 | .getText(ofType(PDDocument::class)) 24 | } returns text 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /android/src/test/kotlin/com/reactnative/pdf/extractor/unit/utils/mocks/UriMock.kt: -------------------------------------------------------------------------------- 1 | package com.reactnative.pdf.extractor.unit.utils.mocks 2 | 3 | import com.reactnative.pdf.extractor.unit.utils.mocks.interfaces.Mock 4 | import io.mockk.mockk 5 | import android.net.Uri 6 | 7 | class UriMock(): Mock { 8 | private var uri = mockk(relaxed = true) 9 | 10 | override fun mock(): Uri { 11 | return uri 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /android/src/test/kotlin/com/reactnative/pdf/extractor/unit/utils/mocks/interfaces/Mock.kt: -------------------------------------------------------------------------------- 1 | package com.reactnative.pdf.extractor.unit.utils.mocks.interfaces 2 | 3 | interface Mock { 4 | fun mock(): Any 5 | } 6 | -------------------------------------------------------------------------------- /android/src/test/kotlin/com/reactnative/pdf/extractor/unit/utils/resources/multiline-formatted.txt: -------------------------------------------------------------------------------- 1 | This is a file 2 | with multiline 3 | text used on 4 | 000.000.000-00 5 | test cases. 6 | name.lastname@mail.com 7 | -------------------------------------------------------------------------------- /android/src/test/kotlin/com/reactnative/pdf/extractor/unit/utils/resources/multiline-unformatted.txt: -------------------------------------------------------------------------------- 1 | This is a file 2 | with multiline 3 | text used on 4 | 000.000.000-00 5 | test cases. 6 | name.lastname@mail.com 7 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | export * from './src/extractors'; 2 | export * from './src/patterns'; 3 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'react-native', 5 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], 6 | modulePathIgnorePatterns: [ 7 | '/example/node_modules', 8 | '/lib/', 9 | ], 10 | setupFiles: ['/.jest/jest.setup.ts'], 11 | setupFilesAfterEnv: ['@testing-library/jest-native/extend-expect'], 12 | }; 13 | 14 | export default config; 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-pdf-extractor", 3 | "version": "0.2.6", 4 | "description": "This library allows you to extract pdfs file data using matches specifics patterns.", 5 | "main": "lib/commonjs/index.js", 6 | "module": "lib/module/index.js", 7 | "types": "lib/typescript/src/index.d.ts", 8 | "react-native": "index.ts", 9 | "source": "index.ts", 10 | "scripts": { 11 | "build": "bob build", 12 | "docs": "cd website && yarn install && yarn start", 13 | "lint": "eslint \"src/**/*.{js,ts,tsx}\" \"src/**/**/*.{js,ts,tsx}\" --fix", 14 | "test": "jest --coverage --detectOpenHandles", 15 | "type-check": "tsc --noEmit", 16 | "sonar": "sonar-scanner -Dsonar.host.url=https://sonarcloud.io", 17 | "circular": "madge --circular index.ts --no-spinner --warning" 18 | }, 19 | "keywords": [ 20 | "react-native", 21 | "android", 22 | "pdf", 23 | "extract" 24 | ], 25 | "repository": "https://github.com/1fabiopereira/react-native-pdf-extractor", 26 | "author": "Fábio Pereira (https://github.com/1fabiopereira)", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/1fabiopereira/react-native-pdf-extractor/issues" 30 | }, 31 | "homepage": "https://1fabiopereira.github.io/react-native-pdf-extractor", 32 | "publishConfig": { 33 | "registry": "https://registry.npmjs.org/" 34 | }, 35 | "devDependencies": { 36 | "@commitlint/config-conventional": "^17.0.2", 37 | "@react-native-community/eslint-config": "^3.0.2", 38 | "@release-it/conventional-changelog": "^5.0.0", 39 | "@testing-library/jest-native": "^5.4.2", 40 | "@testing-library/react-native": "^12.1.2", 41 | "@types/jest": "^29.1.2", 42 | "@types/react-native": "0.67.8", 43 | "@types/react": "^18.0.12", 44 | "commitlint": "^17.0.2", 45 | "eslint-config-prettier": "^8.5.0", 46 | "eslint-plugin-prettier": "^4.0.0", 47 | "eslint": "^8.17.0", 48 | "husky": "^8.0.1", 49 | "jest": "^28.1.1", 50 | "madge": "^5.0.1", 51 | "prettier": "^2.6.2", 52 | "react-native-builder-bob": "^0.18.2", 53 | "react-native-modal": "^13.0.1", 54 | "react-native": "0.68.2", 55 | "react-test-renderer": "^18.2.0", 56 | "react": "18.1.0", 57 | "release-it": "^15.0.0", 58 | "sonar-scanner": "^3.1.0", 59 | "ts-node": "^10.9.1", 60 | "typescript": "^4.7.3" 61 | }, 62 | "peerDependencies": { 63 | "react": "*", 64 | "react-native": "*", 65 | "react-native-modal": "*" 66 | }, 67 | "commitlint": { 68 | "extends": [ 69 | "@commitlint/config-conventional" 70 | ] 71 | }, 72 | "eslintConfig": { 73 | "root": true, 74 | "extends": [ 75 | "@react-native-community", 76 | "prettier" 77 | ], 78 | "rules": { 79 | "prettier/prettier": [ 80 | "error", 81 | { 82 | "quoteProps": "consistent", 83 | "singleQuote": true, 84 | "tabWidth": 2, 85 | "trailingComma": "es5", 86 | "useTabs": false 87 | } 88 | ] 89 | } 90 | }, 91 | "eslintIgnore": [ 92 | "node_modules/", 93 | "lib/" 94 | ], 95 | "prettier": { 96 | "quoteProps": "consistent", 97 | "singleQuote": true, 98 | "tabWidth": 2, 99 | "trailingComma": "es5", 100 | "useTabs": false 101 | }, 102 | "react-native-builder-bob": { 103 | "source": "src", 104 | "output": "lib", 105 | "targets": [ 106 | "commonjs", 107 | "module", 108 | "typescript" 109 | ] 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /sample/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | import com.android.build.OutputFile 4 | 5 | /** 6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 7 | * and bundleReleaseJsAndAssets). 8 | * These basically call `react-native bundle` with the correct arguments during the Android build 9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 10 | * bundle directly from the development server. Below you can see all the possible configurations 11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 12 | * `apply from: "../../node_modules/react-native/react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation 19 | * entryFile: "index.android.js", 20 | * 21 | * // https://reactnative.dev/docs/performance#enable-the-ram-format 22 | * bundleCommand: "ram-bundle", 23 | * 24 | * // whether to bundle JS and assets in debug mode 25 | * bundleInDebug: false, 26 | * 27 | * // whether to bundle JS and assets in release mode 28 | * bundleInRelease: true, 29 | * 30 | * // whether to bundle JS and assets in another build variant (if configured). 31 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 32 | * // The configuration property can be in the following formats 33 | * // 'bundleIn${productFlavor}${buildType}' 34 | * // 'bundleIn${buildType}' 35 | * // bundleInFreeDebug: true, 36 | * // bundleInPaidRelease: true, 37 | * // bundleInBeta: true, 38 | * 39 | * // whether to disable dev mode in custom build variants (by default only disabled in release) 40 | * // for PdfExtractorExample: to disable dev mode in the staging build type (if configured) 41 | * devDisabledInStaging: true, 42 | * // The configuration property can be in the following formats 43 | * // 'devDisabledIn${productFlavor}${buildType}' 44 | * // 'devDisabledIn${buildType}' 45 | * 46 | * // the root of your project, i.e. where "package.json" lives 47 | * root: "../../", 48 | * 49 | * // where to put the JS bundle asset in debug mode 50 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 51 | * 52 | * // where to put the JS bundle asset in release mode 53 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 54 | * 55 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 56 | * // require('./image.png')), in debug mode 57 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 58 | * 59 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 60 | * // require('./image.png')), in release mode 61 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 62 | * 63 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 64 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 65 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 66 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 67 | * // for PdfExtractorExample, you might want to remove it from here. 68 | * inputExcludes: ["android/**", "ios/**"], 69 | * 70 | * // override which node gets called and with what additional arguments 71 | * nodeExecutableAndArgs: ["node"], 72 | * 73 | * // supply additional arguments to the packager 74 | * extraPackagerArgs: [] 75 | * ] 76 | */ 77 | 78 | project.ext.react = [ 79 | enableHermes: false, // clean and rebuild if changing 80 | entryFile: "index.tsx", 81 | ] 82 | 83 | apply from: "../../node_modules/react-native/react.gradle" 84 | 85 | /** 86 | * Set this to true to create two separate APKs instead of one: 87 | * - An APK that only works on ARM devices 88 | * - An APK that only works on x86 devices 89 | * The advantage is the size of the APK is reduced by about 4MB. 90 | * Upload all the APKs to the Play Store and people will download 91 | * the correct one based on the CPU architecture of their device. 92 | */ 93 | def enableSeparateBuildPerCPUArchitecture = false 94 | 95 | /** 96 | * Run Proguard to shrink the Java bytecode in release builds. 97 | */ 98 | def enableProguardInReleaseBuilds = true 99 | 100 | /** 101 | * The preferred build flavor of JavaScriptCore. 102 | * 103 | * For PdfExtractorExample, to use the international variant, you can use: 104 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` 105 | * 106 | * The international variant includes ICU i18n library and necessary data 107 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that 108 | * give correct results when using with locales other than en-US. Note that 109 | * this variant is about 6MiB larger per architecture than default. 110 | */ 111 | def jscFlavor = 'org.webkit:android-jsc:+' 112 | 113 | /** 114 | * Whether to enable the Hermes VM. 115 | * 116 | * This should be set on project.ext.react and that value will be read here. If it is not set 117 | * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode 118 | * and the benefits of using Hermes will therefore be sharply reduced. 119 | */ 120 | def enableHermes = project.ext.react.get("enableHermes", false); 121 | 122 | /** 123 | * Architectures to build native code for. 124 | */ 125 | def reactNativeArchitectures() { 126 | def value = project.getProperties().get("reactNativeArchitectures") 127 | return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] 128 | } 129 | 130 | android { 131 | compileSdkVersion rootProject.ext.compileSdkVersion 132 | ndkVersion rootProject.ext.ndkVersion 133 | 134 | defaultConfig { 135 | multiDexEnabled true 136 | applicationId "com.example.reactnativepdfextractor" 137 | minSdkVersion rootProject.ext.minSdkVersion 138 | targetSdkVersion rootProject.ext.targetSdkVersion 139 | versionCode 1 140 | versionName "0.1.2" 141 | } 142 | 143 | splits { 144 | abi { 145 | reset() 146 | enable enableSeparateBuildPerCPUArchitecture 147 | universalApk false // If true, also generate a universal APK 148 | include "armeabi-v7a", "x86", "arm64-v8a", "x86_64" 149 | } 150 | } 151 | 152 | signingConfigs { 153 | debug { 154 | storeFile file('debug.keystore') 155 | storePassword 'android' 156 | keyAlias 'androiddebugkey' 157 | keyPassword 'android' 158 | } 159 | } 160 | 161 | packagingOptions { 162 | exclude 'META-INF/com.android.tools/proguard/coroutines.pro' 163 | } 164 | 165 | buildTypes { 166 | debug { 167 | debuggable true 168 | signingConfig signingConfigs.debug 169 | } 170 | 171 | release { 172 | debuggable false 173 | signingConfig signingConfigs.debug 174 | minifyEnabled enableProguardInReleaseBuilds 175 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 176 | } 177 | } 178 | // applicationVariants are e.g. debug, release 179 | applicationVariants.all { variant -> 180 | variant.outputs.each { output -> 181 | // For each separate APK per architecture, set a unique version code as described here: 182 | // https://developer.android.com/studio/build/configure-apk-splits.html 183 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] 184 | def abi = output.getFilter(OutputFile.ABI) 185 | if (abi != null) { // null for the universal-debug, universal-release variants 186 | output.versionCodeOverride = 187 | defaultConfig.versionCode * 1000 + versionCodes.get(abi) 188 | } 189 | } 190 | } 191 | } 192 | 193 | dependencies { 194 | implementation fileTree(dir: "libs", include: ["*.jar"]) 195 | implementation "com.facebook.react:react-native:+" 196 | implementation ("com.android.support:multidex:1.0.3") 197 | implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' 198 | 199 | implementation project(':react-native-pdf-extractor') 200 | implementation project(':react-native-document-picker') 201 | 202 | if (enableHermes) { 203 | def hermesPath = "../../node_modules/hermes-engine/android/"; 204 | debugImplementation files(hermesPath + "hermes-debug.aar") 205 | releaseImplementation files(hermesPath + "hermes-release.aar") 206 | } else { 207 | implementation jscFlavor 208 | } 209 | } 210 | 211 | // Run this once to be able to run the application with BUCK 212 | // puts all compile dependencies into folder libs for BUCK to use 213 | task copyDownloadableDepsToLibs(type: Copy) { 214 | from configurations.implementation 215 | into 'libs' 216 | } 217 | 218 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); 219 | applyNativeModulesAppBuildGradle(project) 220 | -------------------------------------------------------------------------------- /sample/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pdf-extractor/2a5bc1301a287438a20a3b74e8a2caa0e905b2d0/sample/android/app/debug.keystore -------------------------------------------------------------------------------- /sample/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | -keep class com.facebook.hermes.unicode.** { *; } 13 | -keep class com.facebook.jni.** { *; } -------------------------------------------------------------------------------- /sample/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /sample/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /sample/android/app/src/main/java/com/example/reactnativepdfextractor/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.reactnativepdfextractor; 2 | 3 | import android.os.Bundle; 4 | import android.os.PersistableBundle; 5 | 6 | import androidx.annotation.Nullable; 7 | import com.facebook.react.ReactActivity; 8 | 9 | public class MainActivity extends ReactActivity { 10 | @Override 11 | public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { 12 | super.onCreate(savedInstanceState, persistentState); 13 | } 14 | 15 | @Override 16 | protected String getMainComponentName() { 17 | return "PdfExtractorExample"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /sample/android/app/src/main/java/com/example/reactnativepdfextractor/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.reactnativepdfextractor; 2 | 3 | import android.app.Application; 4 | import com.facebook.react.PackageList; 5 | import com.facebook.react.ReactApplication; 6 | import com.facebook.react.ReactNativeHost; 7 | import com.facebook.react.ReactPackage; 8 | import java.util.List; 9 | 10 | import com.facebook.soloader.SoLoader; 11 | import com.reactnative.pdf.extractor.PdfExtractorPackage; 12 | 13 | public class MainApplication extends Application implements ReactApplication { 14 | 15 | private final ReactNativeHost mReactNativeHost = 16 | new ReactNativeHost(this) { 17 | @Override 18 | public boolean getUseDeveloperSupport() { 19 | return true; 20 | } 21 | 22 | @Override 23 | protected List getPackages() { 24 | List packages = new PackageList(this).getPackages(); 25 | packages.add(new PdfExtractorPackage()); 26 | return packages; 27 | } 28 | 29 | @Override 30 | protected String getJSMainModuleName() { 31 | return "index"; 32 | } 33 | }; 34 | 35 | @Override 36 | public ReactNativeHost getReactNativeHost() { 37 | return mReactNativeHost; 38 | } 39 | 40 | @Override 41 | public void onCreate() { 42 | super.onCreate(); 43 | SoLoader.init(this, false); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /sample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pdf-extractor/2a5bc1301a287438a20a3b74e8a2caa0e905b2d0/sample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pdf-extractor/2a5bc1301a287438a20a3b74e8a2caa0e905b2d0/sample/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pdf-extractor/2a5bc1301a287438a20a3b74e8a2caa0e905b2d0/sample/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pdf-extractor/2a5bc1301a287438a20a3b74e8a2caa0e905b2d0/sample/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pdf-extractor/2a5bc1301a287438a20a3b74e8a2caa0e905b2d0/sample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pdf-extractor/2a5bc1301a287438a20a3b74e8a2caa0e905b2d0/sample/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pdf-extractor/2a5bc1301a287438a20a3b74e8a2caa0e905b2d0/sample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pdf-extractor/2a5bc1301a287438a20a3b74e8a2caa0e905b2d0/sample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pdf-extractor/2a5bc1301a287438a20a3b74e8a2caa0e905b2d0/sample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pdf-extractor/2a5bc1301a287438a20a3b74e8a2caa0e905b2d0/sample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | PDF Extractor Example 3 | 4 | -------------------------------------------------------------------------------- /sample/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /sample/android/app/src/main/res/xml/provider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /sample/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | buildToolsVersion = "31.0.0" 4 | compileSdkVersion = 31 5 | KotlinVersion = "1.6.21" 6 | minSdkVersion = 21 7 | ndkVersion = "21.4.7075529" 8 | targetSdkVersion = 31 9 | } 10 | 11 | repositories { 12 | google() 13 | mavenCentral() 14 | } 15 | 16 | dependencies { 17 | classpath('com.android.tools.build:gradle:7.1.3') 18 | classpath("com.facebook.react:react-native-gradle-plugin") 19 | classpath("de.undercouch:gradle-download-task:4.1.2") 20 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$KotlinVersion") 21 | } 22 | } 23 | 24 | allprojects { 25 | repositories { 26 | maven { 27 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 28 | url("$rootDir/../node_modules/react-native/android") 29 | } 30 | 31 | maven { 32 | // Android JSC is installed from npm 33 | url("$rootDir/../node_modules/jsc-android/dist") 34 | } 35 | 36 | mavenCentral { 37 | // We don't want to fetch react-native from Maven Central as there are 38 | // older versions over there. 39 | content { 40 | excludeGroup "com.facebook.react" 41 | } 42 | } 43 | 44 | google() 45 | 46 | maven { url 'https://www.jitpack.io' } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /sample/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useAndroidX=true 21 | android.enableJetifier=true 22 | -------------------------------------------------------------------------------- /sample/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pdf-extractor/2a5bc1301a287438a20a3b74e8a2caa0e905b2d0/sample/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /sample/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /sample/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" -------------------------------------------------------------------------------- /sample/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega -------------------------------------------------------------------------------- /sample/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'PdfExtractorExample' 2 | 3 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); 4 | applyNativeModulesSettingsGradle(settings) 5 | 6 | include ':app' 7 | 8 | include ':react-native-pdf-extractor' 9 | project(':react-native-pdf-extractor').projectDir = new File(rootProject.projectDir, '../../android') 10 | 11 | includeBuild('../../node_modules/react-native-gradle-plugin') 12 | -------------------------------------------------------------------------------- /sample/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PdfExtractorExample", 3 | "displayName": "PDF Extractor Example" 4 | } 5 | -------------------------------------------------------------------------------- /sample/babel.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = { 5 | presets: ['module:metro-react-native-babel-preset'], 6 | plugins: [ 7 | [ 8 | 'module-resolver', 9 | { 10 | extensions: ['.tsx', '.ts', '.js', '.json'], 11 | alias: { 12 | [pak.name]: path.join(__dirname, '..', pak.source), 13 | }, 14 | }, 15 | ], 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /sample/index.tsx: -------------------------------------------------------------------------------- 1 | import { AppRegistry } from 'react-native'; 2 | import App from './src/App'; 3 | import { name as appName } from './app.json'; 4 | 5 | AppRegistry.registerComponent(appName, () => App); 6 | -------------------------------------------------------------------------------- /sample/metro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const blacklist = require('metro-config/src/defaults/exclusionList'); 3 | const escape = require('escape-string-regexp'); 4 | const pak = require('../package.json'); 5 | 6 | const root = path.resolve(__dirname, '..'); 7 | 8 | const modules = Object.keys({ 9 | ...pak.peerDependencies, 10 | }); 11 | 12 | module.exports = { 13 | projectRoot: __dirname, 14 | watchFolders: [root], 15 | 16 | // We need to make sure that only one version is loaded for peerDependencies 17 | // So we blacklist them at the root, and alias them to the versions in example's node_modules 18 | resolver: { 19 | blacklistRE: blacklist( 20 | modules.map( 21 | (m) => 22 | new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) 23 | ) 24 | ), 25 | 26 | extraNodeModules: modules.reduce((acc, name) => { 27 | acc[name] = path.join(__dirname, 'node_modules', name); 28 | return acc; 29 | }, {}), 30 | }, 31 | 32 | transformer: { 33 | getTransformOptions: async () => ({ 34 | transform: { 35 | experimentalImportSupport: false, 36 | inlineRequires: true, 37 | }, 38 | }), 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /sample/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-pdf-extractor-example", 3 | "description": "Sample app for react-native-pdf-extractor", 4 | "version": "0.1.0", 5 | "private": true, 6 | "scripts": { 7 | "android": "react-native run-android", 8 | "ios": "react-native run-ios", 9 | "start": "react-native start" 10 | }, 11 | "dependencies": { 12 | "react": "18.1.0", 13 | "react-native": "0.64.1", 14 | "react-native-document-picker": "^8.1.1" 15 | }, 16 | "devDependencies": { 17 | "@babel/core": "^7.18.2", 18 | "@babel/runtime": "^7.18.3", 19 | "@react-native-community/cli-platform-android": "^11.3.2", 20 | "@types/react-native-document-picker": "^3.1.1", 21 | "babel-plugin-module-resolver": "^4.1.0", 22 | "metro-react-native-babel-preset": "^0.71.1", 23 | "react-native-modal": "^13.0.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, memo } from 'react'; 2 | import { Button, FlatList, StyleSheet, Text, View } from 'react-native'; 3 | import DocumentPicker from 'react-native-document-picker'; 4 | 5 | import { Extractor, Patterns } from '../..'; 6 | import { Transient } from '../../src/types'; 7 | 8 | const App: React.FC = (): JSX.Element => { 9 | const [isEncrypted, setIsEncrypted] = useState(false); 10 | const [pages, setPages] = useState(0); 11 | const [result, setResult] = useState([]); 12 | const [uri, setUri] = useState(); 13 | const [time, setTime] = useState(); 14 | 15 | const selectFile = async () => { 16 | const data = await DocumentPicker.pickSingle({ 17 | presentationStyle: 'fullScreen', 18 | copyTo: 'cachesDirectory', 19 | type: 'application/pdf', 20 | }); 21 | 22 | setUri(data.uri); 23 | }; 24 | 25 | const onResult = (data: Transient | null) => { 26 | setPages(data?.pages); 27 | setIsEncrypted(data?.isEncrypted); 28 | setUri(data?.uri); 29 | setTime(data?.duration); 30 | setResult(data?.text as string[]); 31 | }; 32 | 33 | return ( 34 | 35 |