├── .config └── dotnet-tools.json ├── .github └── workflows │ ├── dotnet.yml │ └── js.yml ├── .gitignore ├── Benchmarks ├── Benchmarks.fsproj └── Program.fs ├── LICENSE ├── Program.fs ├── README.md ├── Tests.Fable ├── ArraySet.fs ├── Base64.fs ├── SourceMapGenerator.fs ├── SourceNode.fs ├── Tests.Fable.fsproj ├── Tests.fs └── Util.fs ├── Tests ├── ArraySet.fs ├── Base64.fs ├── Program.fs ├── SourceMapGenerator.fs ├── SourceNode.fs ├── Tests.fsproj └── Util.fs ├── package.json ├── pnpm-lock.yaml ├── source-map-sharp.fsproj ├── source-map-sharp.sln └── src ├── ArraySet.fs ├── Base64VLQ.fs ├── FSharpConverters.fs ├── MappingList.fs ├── SourceMapConsumer.fs ├── SourceMapGenerator.fs ├── SourceNode.fs └── Util.fs /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "fable": { 6 | "version": "3.7.0", 7 | "commands": [ 8 | "fable" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | name: Build dotnet 3.1, 5.0, 6.0 & test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build_and_test: 11 | 12 | runs-on: ubuntu-latest 13 | env: 14 | config: 'Release' 15 | strategy: 16 | matrix: 17 | dotnet: ['3.1.x', '5.0.x', '6.0.x'] 18 | steps: 19 | - uses: actions/checkout@v2 20 | - name: Setup .NET 21 | uses: actions/setup-dotnet@v1 22 | with: 23 | dotnet-version: ${{ matrix.dotnet }} 24 | - name: Restore dependencies 25 | run: dotnet restore Tests/Tests.fsproj 26 | - name: Build 27 | run: dotnet build --no-restore Tests/Tests.fsproj 28 | - name: Test 29 | run: dotnet test --no-build --verbosity normal Tests/Tests.fsproj 30 | -------------------------------------------------------------------------------- /.github/workflows/js.yml: -------------------------------------------------------------------------------- 1 | name: Build Fable & test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build_js_and_test: 11 | runs-on: ubuntu-latest 12 | env: 13 | config: 'Release' 14 | strategy: 15 | matrix: 16 | dotnet: ['6.0.x'] 17 | steps: 18 | - uses: actions/checkout@v2 19 | - uses: pnpm/action-setup@v2.0.1 20 | with: 21 | version: latest 22 | - name: Setup .NET 23 | uses: actions/setup-dotnet@v1 24 | with: 25 | dotnet-version: ${{ matrix.dotnet }} 26 | - uses: actions/setup-node@v2 27 | with: 28 | node-version: '16' 29 | cache: 'pnpm' 30 | - name: Restore tools 31 | run: dotnet tool restore 32 | - name: Install 33 | run: pnpm install 34 | - name: Pre-test 35 | run: pnpm run pretest 36 | - name: Test 37 | run: pnpm test 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | /packages/ 4 | riderModule.iml 5 | /_ReSharper.Caches/ 6 | .idea/ 7 | .ionide/ 8 | .vs/ 9 | *.*proj.user 10 | build/ 11 | ### VisualStudioCode template 12 | .vscode/* 13 | !.vscode/settings.json 14 | !.vscode/tasks.json 15 | !.vscode/launch.json 16 | !.vscode/extensions.json 17 | *.code-workspace 18 | 19 | # Local History for Visual Studio Code 20 | .history/ 21 | 22 | ### JetBrains template 23 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 24 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 25 | 26 | # User-specific stuff 27 | .idea/**/workspace.xml 28 | .idea/**/tasks.xml 29 | .idea/**/usage.statistics.xml 30 | .idea/**/dictionaries 31 | .idea/**/shelf 32 | 33 | # Generated files 34 | .idea/**/contentModel.xml 35 | 36 | # Sensitive or high-churn files 37 | .idea/**/dataSources/ 38 | .idea/**/dataSources.ids 39 | .idea/**/dataSources.local.xml 40 | .idea/**/sqlDataSources.xml 41 | .idea/**/dynamic.xml 42 | .idea/**/uiDesigner.xml 43 | .idea/**/dbnavigator.xml 44 | 45 | # Gradle 46 | .idea/**/gradle.xml 47 | .idea/**/libraries 48 | 49 | # Gradle and Maven with auto-import 50 | # When using Gradle or Maven with auto-import, you should exclude module files, 51 | # since they will be recreated, and may cause churn. Uncomment if using 52 | # auto-import. 53 | # .idea/artifacts 54 | # .idea/compiler.xml 55 | # .idea/jarRepositories.xml 56 | # .idea/modules.xml 57 | # .idea/*.iml 58 | # .idea/modules 59 | # *.iml 60 | # *.ipr 61 | 62 | # CMake 63 | cmake-build-*/ 64 | 65 | # Mongo Explorer plugin 66 | .idea/**/mongoSettings.xml 67 | 68 | # File-based project format 69 | *.iws 70 | 71 | # IntelliJ 72 | out/ 73 | 74 | # mpeltonen/sbt-idea plugin 75 | .idea_modules/ 76 | 77 | # JIRA plugin 78 | atlassian-ide-plugin.xml 79 | 80 | # Cursive Clojure plugin 81 | .idea/replstate.xml 82 | 83 | # Crashlytics plugin (for Android Studio and IntelliJ) 84 | com_crashlytics_export_strings.xml 85 | crashlytics.properties 86 | crashlytics-build.properties 87 | fabric.properties 88 | 89 | # Editor-based Rest Client 90 | .idea/httpRequests 91 | 92 | # Android studio 3.1+ serialized cache file 93 | .idea/caches/build_file_checksums.ser 94 | 95 | ### Node template 96 | # Logs 97 | logs 98 | *.log 99 | npm-debug.log* 100 | yarn-debug.log* 101 | yarn-error.log* 102 | lerna-debug.log* 103 | 104 | # Diagnostic reports (https://nodejs.org/api/report.html) 105 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 106 | 107 | # Runtime data 108 | pids 109 | *.pid 110 | *.seed 111 | *.pid.lock 112 | 113 | # Directory for instrumented libs generated by jscoverage/JSCover 114 | lib-cov 115 | 116 | # Coverage directory used by tools like istanbul 117 | coverage 118 | *.lcov 119 | 120 | # nyc test coverage 121 | .nyc_output 122 | 123 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 124 | .grunt 125 | 126 | # Bower dependency directory (https://bower.io/) 127 | bower_components 128 | 129 | # node-waf configuration 130 | .lock-wscript 131 | 132 | # Compiled binary addons (https://nodejs.org/api/addons.html) 133 | build/Release 134 | 135 | # Dependency directories 136 | node_modules/ 137 | jspm_packages/ 138 | 139 | # Snowpack dependency directory (https://snowpack.dev/) 140 | web_modules/ 141 | 142 | # TypeScript cache 143 | *.tsbuildinfo 144 | 145 | # Optional npm cache directory 146 | .npm 147 | 148 | # Optional eslint cache 149 | .eslintcache 150 | 151 | # Microbundle cache 152 | .rpt2_cache/ 153 | .rts2_cache_cjs/ 154 | .rts2_cache_es/ 155 | .rts2_cache_umd/ 156 | 157 | # Optional REPL history 158 | .node_repl_history 159 | 160 | # Output of 'npm pack' 161 | *.tgz 162 | 163 | # Yarn Integrity file 164 | .yarn-integrity 165 | 166 | # dotenv environment variables file 167 | .env 168 | .env.test 169 | 170 | # parcel-bundler cache (https://parceljs.org/) 171 | .cache 172 | .parcel-cache 173 | 174 | # Next.js build output 175 | .next 176 | out 177 | 178 | # Nuxt.js build / generate output 179 | .nuxt 180 | dist 181 | 182 | # Gatsby files 183 | .cache/ 184 | # Comment in the public line in if your project uses Gatsby and not Next.js 185 | # https://nextjs.org/blog/next-9-1#public-directory-support 186 | # public 187 | 188 | # vuepress build output 189 | .vuepress/dist 190 | 191 | # Serverless directories 192 | .serverless/ 193 | 194 | # FuseBox cache 195 | .fusebox/ 196 | 197 | # DynamoDB Local files 198 | .dynamodb/ 199 | 200 | # TernJS port file 201 | .tern-port 202 | 203 | # Stores VSCode versions used for testing VSCode extensions 204 | .vscode-test 205 | 206 | # yarn v2 207 | .yarn/cache 208 | .yarn/unplugged 209 | .yarn/build-state.yml 210 | .yarn/install-state.gz 211 | .pnp.* 212 | 213 | ### VisualStudio template 214 | ## Ignore Visual Studio temporary files, build results, and 215 | ## files generated by popular Visual Studio add-ons. 216 | ## 217 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 218 | 219 | # User-specific files 220 | *.rsuser 221 | *.suo 222 | *.user 223 | *.userosscache 224 | *.sln.docstates 225 | 226 | # User-specific files (MonoDevelop/Xamarin Studio) 227 | *.userprefs 228 | 229 | # Mono auto generated files 230 | mono_crash.* 231 | 232 | # Build results 233 | [Dd]ebug/ 234 | [Dd]ebugPublic/ 235 | [Rr]elease/ 236 | [Rr]eleases/ 237 | x64/ 238 | x86/ 239 | [Ww][Ii][Nn]32/ 240 | [Aa][Rr][Mm]/ 241 | [Aa][Rr][Mm]64/ 242 | bld/ 243 | [Bb]in/ 244 | [Oo]bj/ 245 | [Ll]og/ 246 | [Ll]ogs/ 247 | 248 | # Visual Studio 2015/2017 cache/options directory 249 | # Uncomment if you have tasks that create the project's static files in wwwroot 250 | #wwwroot/ 251 | 252 | # Visual Studio 2017 auto generated files 253 | Generated\ Files/ 254 | 255 | # MSTest test Results 256 | [Tt]est[Rr]esult*/ 257 | [Bb]uild[Ll]og.* 258 | 259 | # NUnit 260 | *.VisualState.xml 261 | TestResult.xml 262 | nunit-*.xml 263 | 264 | # Build Results of an ATL Project 265 | [Dd]ebugPS/ 266 | [Rr]eleasePS/ 267 | dlldata.c 268 | 269 | # Benchmark Results 270 | BenchmarkDotNet.Artifacts/ 271 | 272 | # .NET Core 273 | project.lock.json 274 | project.fragment.lock.json 275 | artifacts/ 276 | 277 | # ASP.NET Scaffolding 278 | ScaffoldingReadMe.txt 279 | 280 | # StyleCop 281 | StyleCopReport.xml 282 | 283 | # Files built by Visual Studio 284 | *_i.c 285 | *_p.c 286 | *_h.h 287 | *.ilk 288 | *.meta 289 | *.obj 290 | *.iobj 291 | *.pch 292 | *.pdb 293 | *.ipdb 294 | *.pgc 295 | *.pgd 296 | *.rsp 297 | *.sbr 298 | *.tlb 299 | *.tli 300 | *.tlh 301 | *.tmp 302 | *.tmp_proj 303 | *_wpftmp.csproj 304 | *.vspscc 305 | *.vssscc 306 | .builds 307 | *.pidb 308 | *.svclog 309 | *.scc 310 | 311 | # Chutzpah Test files 312 | _Chutzpah* 313 | 314 | # Visual C++ cache files 315 | ipch/ 316 | *.aps 317 | *.ncb 318 | *.opendb 319 | *.opensdf 320 | *.sdf 321 | *.cachefile 322 | *.VC.db 323 | *.VC.VC.opendb 324 | 325 | # Visual Studio profiler 326 | *.psess 327 | *.vsp 328 | *.vspx 329 | *.sap 330 | 331 | # Visual Studio Trace Files 332 | *.e2e 333 | 334 | # TFS 2012 Local Workspace 335 | $tf/ 336 | 337 | # Guidance Automation Toolkit 338 | *.gpState 339 | 340 | # ReSharper is a .NET coding add-in 341 | _ReSharper*/ 342 | *.[Rr]e[Ss]harper 343 | *.DotSettings.user 344 | 345 | # TeamCity is a build add-in 346 | _TeamCity* 347 | 348 | # DotCover is a Code Coverage Tool 349 | *.dotCover 350 | 351 | # AxoCover is a Code Coverage Tool 352 | .axoCover/* 353 | !.axoCover/settings.json 354 | 355 | # Coverlet is a free, cross platform Code Coverage Tool 356 | coverage*.json 357 | coverage*.xml 358 | coverage*.info 359 | 360 | # Visual Studio code coverage results 361 | *.coverage 362 | *.coveragexml 363 | 364 | # NCrunch 365 | _NCrunch_* 366 | .*crunch*.local.xml 367 | nCrunchTemp_* 368 | 369 | # MightyMoose 370 | *.mm.* 371 | AutoTest.Net/ 372 | 373 | # Web workbench (sass) 374 | .sass-cache/ 375 | 376 | # Installshield output folder 377 | [Ee]xpress/ 378 | 379 | # DocProject is a documentation generator add-in 380 | DocProject/buildhelp/ 381 | DocProject/Help/*.HxT 382 | DocProject/Help/*.HxC 383 | DocProject/Help/*.hhc 384 | DocProject/Help/*.hhk 385 | DocProject/Help/*.hhp 386 | DocProject/Help/Html2 387 | DocProject/Help/html 388 | 389 | # Click-Once directory 390 | publish/ 391 | 392 | # Publish Web Output 393 | *.[Pp]ublish.xml 394 | *.azurePubxml 395 | # Note: Comment the next line if you want to checkin your web deploy settings, 396 | # but database connection strings (with potential passwords) will be unencrypted 397 | *.pubxml 398 | *.publishproj 399 | 400 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 401 | # checkin your Azure Web App publish settings, but sensitive information contained 402 | # in these scripts will be unencrypted 403 | PublishScripts/ 404 | 405 | # NuGet Packages 406 | *.nupkg 407 | # NuGet Symbol Packages 408 | *.snupkg 409 | # The packages folder can be ignored because of Package Restore 410 | **/[Pp]ackages/* 411 | # except build/, which is used as an MSBuild target. 412 | !**/[Pp]ackages/build/ 413 | # Uncomment if necessary however generally it will be regenerated when needed 414 | #!**/[Pp]ackages/repositories.config 415 | # NuGet v3's project.json files produces more ignorable files 416 | *.nuget.props 417 | *.nuget.targets 418 | 419 | # Microsoft Azure Build Output 420 | csx/ 421 | *.build.csdef 422 | 423 | # Microsoft Azure Emulator 424 | ecf/ 425 | rcf/ 426 | 427 | # Windows Store app package directories and files 428 | AppPackages/ 429 | BundleArtifacts/ 430 | Package.StoreAssociation.xml 431 | _pkginfo.txt 432 | *.appx 433 | *.appxbundle 434 | *.appxupload 435 | 436 | # Visual Studio cache files 437 | # files ending in .cache can be ignored 438 | *.[Cc]ache 439 | # but keep track of directories ending in .cache 440 | !?*.[Cc]ache/ 441 | 442 | # Others 443 | ClientBin/ 444 | ~$* 445 | *~ 446 | *.dbmdl 447 | *.dbproj.schemaview 448 | *.jfm 449 | *.pfx 450 | *.publishsettings 451 | orleans.codegen.cs 452 | 453 | # Including strong name files can present a security risk 454 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 455 | #*.snk 456 | 457 | # Since there are multiple workflows, uncomment next line to ignore bower_components 458 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 459 | #bower_components/ 460 | 461 | # RIA/Silverlight projects 462 | Generated_Code/ 463 | 464 | # Backup & report files from converting an old project file 465 | # to a newer Visual Studio version. Backup files are not needed, 466 | # because we have git ;-) 467 | _UpgradeReport_Files/ 468 | Backup*/ 469 | UpgradeLog*.XML 470 | UpgradeLog*.htm 471 | ServiceFabricBackup/ 472 | *.rptproj.bak 473 | 474 | # SQL Server files 475 | *.mdf 476 | *.ldf 477 | *.ndf 478 | 479 | # Business Intelligence projects 480 | *.rdl.data 481 | *.bim.layout 482 | *.bim_*.settings 483 | *.rptproj.rsuser 484 | *- [Bb]ackup.rdl 485 | *- [Bb]ackup ([0-9]).rdl 486 | *- [Bb]ackup ([0-9][0-9]).rdl 487 | 488 | # Microsoft Fakes 489 | FakesAssemblies/ 490 | 491 | # GhostDoc plugin setting file 492 | *.GhostDoc.xml 493 | 494 | # Node.js Tools for Visual Studio 495 | .ntvs_analysis.dat 496 | 497 | # Visual Studio 6 build log 498 | *.plg 499 | 500 | # Visual Studio 6 workspace options file 501 | *.opt 502 | 503 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 504 | *.vbw 505 | 506 | # Visual Studio LightSwitch build output 507 | **/*.HTMLClient/GeneratedArtifacts 508 | **/*.DesktopClient/GeneratedArtifacts 509 | **/*.DesktopClient/ModelManifest.xml 510 | **/*.Server/GeneratedArtifacts 511 | **/*.Server/ModelManifest.xml 512 | _Pvt_Extensions 513 | 514 | # Paket dependency manager 515 | .paket/paket.exe 516 | paket-files/ 517 | 518 | # FAKE - F# Make 519 | .fake/ 520 | 521 | # CodeRush personal settings 522 | .cr/personal 523 | 524 | # Python Tools for Visual Studio (PTVS) 525 | __pycache__/ 526 | *.pyc 527 | 528 | # Cake - Uncomment if you are using it 529 | # tools/** 530 | # !tools/packages.config 531 | 532 | # Tabs Studio 533 | *.tss 534 | 535 | # Telerik's JustMock configuration file 536 | *.jmconfig 537 | 538 | # BizTalk build output 539 | *.btp.cs 540 | *.btm.cs 541 | *.odx.cs 542 | *.xsd.cs 543 | 544 | # OpenCover UI analysis results 545 | OpenCover/ 546 | 547 | # Azure Stream Analytics local run output 548 | ASALocalRun/ 549 | 550 | # MSBuild Binary and Structured Log 551 | *.binlog 552 | 553 | # NVidia Nsight GPU debugger configuration file 554 | *.nvuser 555 | 556 | # MFractors (Xamarin productivity tool) working folder 557 | .mfractor/ 558 | 559 | # Local History for Visual Studio 560 | .localhistory/ 561 | 562 | # BeatPulse healthcheck temp database 563 | healthchecksdb 564 | 565 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 566 | MigrationBackup/ 567 | 568 | # Ionide (cross platform F# VS Code tools) working folder 569 | 570 | # Fody - auto-generated XML schema 571 | FodyWeavers.xsd 572 | 573 | ### macOS template 574 | # General 575 | .DS_Store 576 | .AppleDouble 577 | .LSOverride 578 | 579 | # Icon must end with two \r 580 | Icon 581 | 582 | # Thumbnails 583 | ._* 584 | 585 | # Files that might appear in the root of a volume 586 | .DocumentRevisions-V100 587 | .fseventsd 588 | .Spotlight-V100 589 | .TemporaryItems 590 | .Trashes 591 | .VolumeIcon.icns 592 | .com.apple.timemachine.donotpresent 593 | 594 | # Directories potentially created on remote AFP share 595 | .AppleDB 596 | .AppleDesktop 597 | Network Trash Folder 598 | Temporary Items 599 | .apdisk 600 | 601 | 602 | 603 | *.fs.js 604 | -------------------------------------------------------------------------------- /Benchmarks/Benchmarks.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net6.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2011, Mozilla Foundation and contributors 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the names of the Mozilla Foundation nor the names of project 15 | contributors may be used to endorse or promote products derived from this 16 | software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Program.fs: -------------------------------------------------------------------------------- 1 | // Learn more about F# at http://docs.microsoft.com/dotnet/fsharp 2 | 3 | open System 4 | open SourceMapSharp 5 | 6 | // Define a function to construct a message to print 7 | let from whom = 8 | sprintf "from %s" whom 9 | 10 | [] 11 | let main argv = 12 | printfn "%A" (Base64Vlq.Encode 0) 13 | 0 // return an integer exit code -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Source Map Sharp 2 | 3 | ![Tests status](https://github.com/delneg/source-map-sharp/workflows/source-map-sharp-action/badge.svg?branch=master) 4 | ## About 5 | 6 | This is a direct rewrite (meaning, the goal was not to write 'idiomatic' F# code, but to resemble inital JS code as close as possible) of source map generation tool https://github.com/mozilla/source-map 7 | 8 | Which is originally written in JS. The initial purpose is to use it with https://github.com/fable-compiler/Fable project 9 | 10 | See https://github.com/fable-compiler/Fable/issues/2166 - "Bring back source map support" 11 | 12 | UPD: The issue above was closed, and this project is now being used by Fable to generated Source Maps. Hooray! 13 | 14 | 15 | ### Current support status 16 | 17 | + Fable - working fine 18 | + .NET - working fine 19 | 20 | ### Running tests 21 | 22 | dotnet: 23 | 24 | `dotnet test` 25 | 26 | Fable (js): 27 | ``` 28 | dotnet tool restore 29 | pnpm install 30 | pnpm test 31 | ``` 32 | 33 | 34 | ### Files - status 35 | 36 | Legend: 37 | 38 | 😊 - Everything fine 39 | 40 | 🤨 - Everything fine except minor details (or not important right now details) 41 | 42 | 😴 - Not needed / won't do 43 | 44 | 😨 - Should be done, but isn't 45 | 46 | 🤯 - Done but no tested 47 | 48 | 1. 😊 `ArraySet` - Done & tested 49 | 2. 😊 `Base64` - Done & tested 50 | 3. 😊 `Base64-vlq` - Done & tested 51 | 4. 😴 `binary-search` - Not done, probably won't need 52 | 5. 🤨 `mapping-list` - Done, not tested specifically, coverage shows 95% via other tessts 53 | 6. 😴 `mapping.wasm` - Not done, probably won't need 54 | 7. 😴 `read-wasm-browser` - Not done, probably won't need 55 | 8. 😴 `read-wasm` - Not done, probably won't need 56 | 9. 😨 `source-map-consumer` - Not done, Don't know if will need it or not at the moment 57 | 10. 😊 `source-map-generator` - Done except the `consumer` parts, tested except `consumer` parts 58 | 11. 😊 `source-node` - Done except the `consumer` parts, tested except `consumer` parts 59 | 12. 😴 `url-browser` - Not done, probably won't need 60 | 13. 😴 `url` - Not done, probably won't need 61 | 14. 🤨 `util` - Done partially, what's needed 62 | 15. 😴 `wasm` - Not done, probably won't need 63 | 64 | #### "SourceMapConsumer"-related stuff 65 | 66 | Not done at the moment: 67 | 68 | 1. SourceNode `fromStringWithSourceMap` function 69 | 2. SourceMapGenerator `fromSourceMap` function 70 | 3. SourceMapConsumer module 71 | 4. SourceMapNode, SourceMapGenerator - `consumer`-related tests 72 | 73 | 74 | ### Help needed 75 | 76 | 1. Source map consumer 77 | 2. Documentation & usage examples 78 | 3. Decisions on WASM stuff - Rust repo https://github.com/fitzgen/source-map-mappings -------------------------------------------------------------------------------- /Tests.Fable/ArraySet.fs: -------------------------------------------------------------------------------- 1 | module Tests_Fable.ArraySet 2 | 3 | open Fable.Mocha 4 | open SourceMapSharp 5 | 6 | 7 | 8 | let makeTestSet () = 9 | let set = ArraySet() 10 | 11 | for i in [ 0 .. 99 ] do 12 | set.Add(string i, false) 13 | 14 | set 15 | 16 | let arraySetTests = 17 | testList "ArraySet" [ 18 | 19 | testCase "test .has() membership" <| fun () -> 20 | let set = makeTestSet () 21 | 22 | for i in [ 0 .. 99 ] do 23 | 24 | Expect.isTrue(set.Has(string i)) "test .has() membership" 25 | 26 | 27 | testCase "test .indexOf() elements" <| fun () -> 28 | let set = makeTestSet () 29 | 30 | for i in [ 0 .. 99 ] do 31 | let a = set.indexOf (string i) 32 | Expect.equal a (Some(i)) "test .indexOf() elements" 33 | 34 | 35 | testCase "test .at() indexing" <| fun () -> 36 | let set = makeTestSet () 37 | 38 | for i in [ 0 .. 99 ] do 39 | let a = set.At(i) 40 | Expect.equal a (Some(string i)) "test .at() indexing" 41 | 42 | 43 | testCase "test creating from an array" <| fun () -> 44 | let set = 45 | ArraySet.fromArray 46 | ([| "foo" 47 | "bar" 48 | "baz" 49 | "quux" 50 | "hasOwnProperty" |], 51 | false) 52 | Expect.isTrue(set.Has("foo")) "foo" 53 | Expect.isTrue(set.Has("bar")) "bar" 54 | Expect.isTrue(set.Has("baz")) "baz" 55 | Expect.isTrue(set.Has("quux")) "quux" 56 | Expect.isTrue(set.Has("hasOwnProperty")) "hasOwnProperty" 57 | 58 | Expect.equal (set.indexOf("foo")) (Some 0) "indexOf foo" 59 | Expect.equal (set.indexOf("bar")) (Some 1) "indexOf bar" 60 | Expect.equal (set.indexOf("baz")) (Some 2) "indexOf baz" 61 | Expect.equal (set.indexOf("quux"))(Some 3) "indexOf quux" 62 | 63 | Expect.equal (set.At(0)) (Some "foo") ".At foo" 64 | Expect.equal (set.At(1)) (Some "bar") ".At bar" 65 | Expect.equal (set.At(2)) (Some "baz") ".At baz" 66 | Expect.equal (set.At(3))(Some "quux") ".At quux" 67 | 68 | 69 | testCase "test that you can add __proto__; see github issue #30" <| fun () -> 70 | let set = ArraySet () 71 | set.Add("__proto__",false) 72 | Expect.isTrue(set.Has("__proto__")) "__proto__ has" 73 | Expect.equal (set.indexOf("__proto__")) (Some(0)) "indexOf __proto__" 74 | Expect.equal (set.At(0)) (Some("__proto__")) ".At __proto__" 75 | 76 | 77 | 78 | testCase "test .fromArray() with duplicates" <| fun () -> 79 | let set = ArraySet.fromArray ([| "foo";"foo"|],false) 80 | 81 | Expect.isTrue (set.Has("foo")) "set has foo" 82 | Expect.equal (set.At(0)) (Some "foo") "set at 0 is foo" 83 | Expect.equal (set.indexOf("foo")) (Some 0) "set indexOf foo is 0" 84 | Expect.equal (set.ToArray().Count) 1 "set toArray count is 1" 85 | 86 | let set = ArraySet.fromArray ([| "foo";"foo"|],true) 87 | 88 | Expect.isTrue (set.Has("foo")) "set has foo" 89 | Expect.equal (set.At(0)) (Some "foo") "set at 0 is foo" 90 | Expect.equal (set.At(1)) (Some "foo") "set at 1 is foo" 91 | Expect.equal (set.indexOf("foo")) (Some 0) "set indexOf foo is 0" 92 | Expect.equal (set.ToArray().Count) 2 "set toArray count is 2" 93 | 94 | 95 | testCase "test .add() with duplicates" <| fun () -> 96 | 97 | let set = ArraySet() 98 | set.Add("foo",false) 99 | set.Add("foo",false) 100 | 101 | Expect.isTrue (set.Has("foo")) "set has foo" 102 | Expect.equal (set.At(0)) (Some "foo") "set at 0 is foo" 103 | Expect.equal (set.indexOf("foo")) (Some 0) "set indexOf foo is 0" 104 | Expect.equal (set.ToArray().Count) 1 "set.ToArray().Count is 1" 105 | 106 | set.Add("foo",true) 107 | 108 | Expect.isTrue (set.Has("foo")) "set has foo" 109 | Expect.equal (set.At(0)) (Some "foo") "set at 0 is foo" 110 | Expect.equal (set.At(1)) (Some "foo") "set at 1 is foo" 111 | Expect.equal (set.indexOf("foo")) (Some 0) "set indexOf foo is 0" 112 | Expect.equal (set.ToArray().Count) 2 "set.ToArray().Count is 2" 113 | 114 | 115 | testCase "test .size()" <| fun () -> 116 | let set = ArraySet () 117 | set.Add("foo",false) 118 | set.Add("bar",false) 119 | set.Add("baz",false) 120 | Expect.equal (set.Size()) 3 ".size() == 3" 121 | 122 | 123 | testCase "test .size() with disallowed duplicates" <| fun () -> 124 | let set = ArraySet () 125 | set.Add("foo",false) 126 | set.Add("foo",false) 127 | set.Add("bar",false) 128 | set.Add("bar",false) 129 | set.Add("baz",false) 130 | set.Add("baz",false) 131 | Expect.equal (set.Size()) 3 ".size() with disallowed duplicates == 3" 132 | 133 | 134 | testCase "test .size() with allowed duplicates" <| fun () -> 135 | let set = ArraySet () 136 | set.Add("foo",false) 137 | set.Add("foo",true) 138 | set.Add("bar",false) 139 | set.Add("bar",true) 140 | set.Add("baz",false) 141 | set.Add("baz",true) 142 | Expect.equal (set.Size()) 3 ".size() with allowed duplicates == 3" 143 | ] 144 | -------------------------------------------------------------------------------- /Tests.Fable/Base64.fs: -------------------------------------------------------------------------------- 1 | module Tests_Fable.Base64 2 | 3 | open Fable.Core 4 | open Fable.Mocha 5 | open SourceMapSharp 6 | 7 | let vlqs = 8 | [| (-255, "/P") 9 | (-254, "9P") 10 | (-253, "7P") 11 | (-252, "5P") 12 | (-251, "3P") 13 | (-250, "1P") 14 | (-249, "zP") 15 | (-248, "xP") 16 | (-247, "vP") 17 | (-246, "tP") 18 | (-245, "rP") 19 | (-244, "pP") 20 | (-243, "nP") 21 | (-242, "lP") 22 | (-241, "jP") 23 | (-240, "hP") 24 | (-239, "/O") 25 | (-238, "9O") 26 | (-237, "7O") 27 | (-236, "5O") 28 | (-235, "3O") 29 | (-234, "1O") 30 | (-233, "zO") 31 | (-232, "xO") 32 | (-231, "vO") 33 | (-230, "tO") 34 | (-229, "rO") 35 | (-228, "pO") 36 | (-227, "nO") 37 | (-226, "lO") 38 | (-225, "jO") 39 | (-224, "hO") 40 | (-223, "/N") 41 | (-222, "9N") 42 | (-221, "7N") 43 | (-220, "5N") 44 | (-219, "3N") 45 | (-218, "1N") 46 | (-217, "zN") 47 | (-216, "xN") 48 | (-215, "vN") 49 | (-214, "tN") 50 | (-213, "rN") 51 | (-212, "pN") 52 | (-211, "nN") 53 | (-210, "lN") 54 | (-209, "jN") 55 | (-208, "hN") 56 | (-207, "/M") 57 | (-206, "9M") 58 | (-205, "7M") 59 | (-204, "5M") 60 | (-203, "3M") 61 | (-202, "1M") 62 | (-201, "zM") 63 | (-200, "xM") 64 | (-199, "vM") 65 | (-198, "tM") 66 | (-197, "rM") 67 | (-196, "pM") 68 | (-195, "nM") 69 | (-194, "lM") 70 | (-193, "jM") 71 | (-192, "hM") 72 | (-191, "/L") 73 | (-190, "9L") 74 | (-189, "7L") 75 | (-188, "5L") 76 | (-187, "3L") 77 | (-186, "1L") 78 | (-185, "zL") 79 | (-184, "xL") 80 | (-183, "vL") 81 | (-182, "tL") 82 | (-181, "rL") 83 | (-180, "pL") 84 | (-179, "nL") 85 | (-178, "lL") 86 | (-177, "jL") 87 | (-176, "hL") 88 | (-175, "/K") 89 | (-174, "9K") 90 | (-173, "7K") 91 | (-172, "5K") 92 | (-171, "3K") 93 | (-170, "1K") 94 | (-169, "zK") 95 | (-168, "xK") 96 | (-167, "vK") 97 | (-166, "tK") 98 | (-165, "rK") 99 | (-164, "pK") 100 | (-163, "nK") 101 | (-162, "lK") 102 | (-161, "jK") 103 | (-160, "hK") 104 | (-159, "/J") 105 | (-158, "9J") 106 | (-157, "7J") 107 | (-156, "5J") 108 | (-155, "3J") 109 | (-154, "1J") 110 | (-153, "zJ") 111 | (-152, "xJ") 112 | (-151, "vJ") 113 | (-150, "tJ") 114 | (-149, "rJ") 115 | (-148, "pJ") 116 | (-147, "nJ") 117 | (-146, "lJ") 118 | (-145, "jJ") 119 | (-144, "hJ") 120 | (-143, "/I") 121 | (-142, "9I") 122 | (-141, "7I") 123 | (-140, "5I") 124 | (-139, "3I") 125 | (-138, "1I") 126 | (-137, "zI") 127 | (-136, "xI") 128 | (-135, "vI") 129 | (-134, "tI") 130 | (-133, "rI") 131 | (-132, "pI") 132 | (-131, "nI") 133 | (-130, "lI") 134 | (-129, "jI") 135 | (-128, "hI") 136 | (-127, "/H") 137 | (-126, "9H") 138 | (-125, "7H") 139 | (-124, "5H") 140 | (-123, "3H") 141 | (-122, "1H") 142 | (-121, "zH") 143 | (-120, "xH") 144 | (-119, "vH") 145 | (-118, "tH") 146 | (-117, "rH") 147 | (-116, "pH") 148 | (-115, "nH") 149 | (-114, "lH") 150 | (-113, "jH") 151 | (-112, "hH") 152 | (-111, "/G") 153 | (-110, "9G") 154 | (-109, "7G") 155 | (-108, "5G") 156 | (-107, "3G") 157 | (-106, "1G") 158 | (-105, "zG") 159 | (-104, "xG") 160 | (-103, "vG") 161 | (-102, "tG") 162 | (-101, "rG") 163 | (-100, "pG") 164 | (-99, "nG") 165 | (-98, "lG") 166 | (-97, "jG") 167 | (-96, "hG") 168 | (-95, "/F") 169 | (-94, "9F") 170 | (-93, "7F") 171 | (-92, "5F") 172 | (-91, "3F") 173 | (-90, "1F") 174 | (-89, "zF") 175 | (-88, "xF") 176 | (-87, "vF") 177 | (-86, "tF") 178 | (-85, "rF") 179 | (-84, "pF") 180 | (-83, "nF") 181 | (-82, "lF") 182 | (-81, "jF") 183 | (-80, "hF") 184 | (-79, "/E") 185 | (-78, "9E") 186 | (-77, "7E") 187 | (-76, "5E") 188 | (-75, "3E") 189 | (-74, "1E") 190 | (-73, "zE") 191 | (-72, "xE") 192 | (-71, "vE") 193 | (-70, "tE") 194 | (-69, "rE") 195 | (-68, "pE") 196 | (-67, "nE") 197 | (-66, "lE") 198 | (-65, "jE") 199 | (-64, "hE") 200 | (-63, "/D") 201 | (-62, "9D") 202 | (-61, "7D") 203 | (-60, "5D") 204 | (-59, "3D") 205 | (-58, "1D") 206 | (-57, "zD") 207 | (-56, "xD") 208 | (-55, "vD") 209 | (-54, "tD") 210 | (-53, "rD") 211 | (-52, "pD") 212 | (-51, "nD") 213 | (-50, "lD") 214 | (-49, "jD") 215 | (-48, "hD") 216 | (-47, "/C") 217 | (-46, "9C") 218 | (-45, "7C") 219 | (-44, "5C") 220 | (-43, "3C") 221 | (-42, "1C") 222 | (-41, "zC") 223 | (-40, "xC") 224 | (-39, "vC") 225 | (-38, "tC") 226 | (-37, "rC") 227 | (-36, "pC") 228 | (-35, "nC") 229 | (-34, "lC") 230 | (-33, "jC") 231 | (-32, "hC") 232 | (-31, "/B") 233 | (-30, "9B") 234 | (-29, "7B") 235 | (-28, "5B") 236 | (-27, "3B") 237 | (-26, "1B") 238 | (-25, "zB") 239 | (-24, "xB") 240 | (-23, "vB") 241 | (-22, "tB") 242 | (-21, "rB") 243 | (-20, "pB") 244 | (-19, "nB") 245 | (-18, "lB") 246 | (-17, "jB") 247 | (-16, "hB") 248 | (-15, "f") 249 | (-14, "d") 250 | (-13, "b") 251 | (-12, "Z") 252 | (-11, "X") 253 | (-10, "V") 254 | (-9, "T") 255 | (-8, "R") 256 | (-7, "P") 257 | (-6, "N") 258 | (-5, "L") 259 | (-4, "J") 260 | (-3, "H") 261 | (-2, "F") 262 | (-1, "D") 263 | (0, "A") 264 | (1, "C") 265 | (2, "E") 266 | (3, "G") 267 | (4, "I") 268 | (5, "K") 269 | (6, "M") 270 | (7, "O") 271 | (8, "Q") 272 | (9, "S") 273 | (10, "U") 274 | (11, "W") 275 | (12, "Y") 276 | (13, "a") 277 | (14, "c") 278 | (15, "e") 279 | (16, "gB") 280 | (17, "iB") 281 | (18, "kB") 282 | (19, "mB") 283 | (20, "oB") 284 | (21, "qB") 285 | (22, "sB") 286 | (23, "uB") 287 | (24, "wB") 288 | (25, "yB") 289 | (26, "0B") 290 | (27, "2B") 291 | (28, "4B") 292 | (29, "6B") 293 | (30, "8B") 294 | (31, "+B") 295 | (32, "gC") 296 | (33, "iC") 297 | (34, "kC") 298 | (35, "mC") 299 | (36, "oC") 300 | (37, "qC") 301 | (38, "sC") 302 | (39, "uC") 303 | (40, "wC") 304 | (41, "yC") 305 | (42, "0C") 306 | (43, "2C") 307 | (44, "4C") 308 | (45, "6C") 309 | (46, "8C") 310 | (47, "+C") 311 | (48, "gD") 312 | (49, "iD") 313 | (50, "kD") 314 | (51, "mD") 315 | (52, "oD") 316 | (53, "qD") 317 | (54, "sD") 318 | (55, "uD") 319 | (56, "wD") 320 | (57, "yD") 321 | (58, "0D") 322 | (59, "2D") 323 | (60, "4D") 324 | (61, "6D") 325 | (62, "8D") 326 | (63, "+D") 327 | (64, "gE") 328 | (65, "iE") 329 | (66, "kE") 330 | (67, "mE") 331 | (68, "oE") 332 | (69, "qE") 333 | (70, "sE") 334 | (71, "uE") 335 | (72, "wE") 336 | (73, "yE") 337 | (74, "0E") 338 | (75, "2E") 339 | (76, "4E") 340 | (77, "6E") 341 | (78, "8E") 342 | (79, "+E") 343 | (80, "gF") 344 | (81, "iF") 345 | (82, "kF") 346 | (83, "mF") 347 | (84, "oF") 348 | (85, "qF") 349 | (86, "sF") 350 | (87, "uF") 351 | (88, "wF") 352 | (89, "yF") 353 | (90, "0F") 354 | (91, "2F") 355 | (92, "4F") 356 | (93, "6F") 357 | (94, "8F") 358 | (95, "+F") 359 | (96, "gG") 360 | (97, "iG") 361 | (98, "kG") 362 | (99, "mG") 363 | (100, "oG") 364 | (101, "qG") 365 | (102, "sG") 366 | (103, "uG") 367 | (104, "wG") 368 | (105, "yG") 369 | (106, "0G") 370 | (107, "2G") 371 | (108, "4G") 372 | (109, "6G") 373 | (110, "8G") 374 | (111, "+G") 375 | (112, "gH") 376 | (113, "iH") 377 | (114, "kH") 378 | (115, "mH") 379 | (116, "oH") 380 | (117, "qH") 381 | (118, "sH") 382 | (119, "uH") 383 | (120, "wH") 384 | (121, "yH") 385 | (122, "0H") 386 | (123, "2H") 387 | (124, "4H") 388 | (125, "6H") 389 | (126, "8H") 390 | (127, "+H") 391 | (128, "gI") 392 | (129, "iI") 393 | (130, "kI") 394 | (131, "mI") 395 | (132, "oI") 396 | (133, "qI") 397 | (134, "sI") 398 | (135, "uI") 399 | (136, "wI") 400 | (137, "yI") 401 | (138, "0I") 402 | (139, "2I") 403 | (140, "4I") 404 | (141, "6I") 405 | (142, "8I") 406 | (143, "+I") 407 | (144, "gJ") 408 | (145, "iJ") 409 | (146, "kJ") 410 | (147, "mJ") 411 | (148, "oJ") 412 | (149, "qJ") 413 | (150, "sJ") 414 | (151, "uJ") 415 | (152, "wJ") 416 | (157, "6J") 417 | (158, "8J") 418 | (159, "+J") 419 | (160, "gK") 420 | (161, "iK") 421 | (162, "kK") 422 | (163, "mK") 423 | (164, "oK") 424 | (165, "qK") 425 | (166, "sK") 426 | (167, "uK") 427 | (168, "wK") 428 | (169, "yK") 429 | (170, "0K") 430 | (171, "2K") 431 | (172, "4K") 432 | (173, "6K") 433 | (174, "8K") 434 | (175, "+K") 435 | (176, "gL") 436 | (177, "iL") 437 | (178, "kL") 438 | (179, "mL") 439 | (180, "oL") 440 | (181, "qL") 441 | (182, "sL") 442 | (183, "uL") 443 | (184, "wL") 444 | (185, "yL") 445 | (186, "0L") 446 | (187, "2L") 447 | (188, "4L") 448 | (189, "6L") 449 | (190, "8L") 450 | (191, "+L") 451 | (192, "gM") 452 | (193, "iM") 453 | (194, "kM") 454 | (195, "mM") 455 | (196, "oM") 456 | (197, "qM") 457 | (198, "sM") 458 | (199, "uM") 459 | (200, "wM") 460 | (201, "yM") 461 | (202, "0M") 462 | (203, "2M") 463 | (204, "4M") 464 | (205, "6M") 465 | (206, "8M") 466 | (207, "+M") 467 | (208, "gN") 468 | (209, "iN") 469 | (210, "kN") 470 | (211, "mN") 471 | (212, "oN") 472 | (213, "qN") 473 | (214, "sN") 474 | (215, "uN") 475 | (216, "wN") 476 | (217, "yN") 477 | (218, "0N") 478 | (219, "2N") 479 | (220, "4N") 480 | (221, "6N") 481 | (222, "8N") 482 | (223, "+N") 483 | (224, "gO") 484 | (225, "iO") 485 | (226, "kO") 486 | (227, "mO") 487 | (228, "oO") 488 | (229, "qO") 489 | (230, "sO") 490 | (231, "uO") 491 | (232, "wO") 492 | (233, "yO") 493 | (234, "0O") 494 | (235, "2O") 495 | (236, "4O") 496 | (237, "6O") 497 | (238, "8O") 498 | (239, "+O") 499 | (240, "gP") 500 | (241, "iP") 501 | (242, "kP") 502 | (243, "mP") 503 | (244, "oP") 504 | (245, "qP") 505 | (246, "sP") 506 | (247, "uP") 507 | (248, "wP") 508 | (249, "yP") 509 | (250, "0P") 510 | (251, "2P") 511 | (252, "4P") 512 | (253, "6P") 513 | (254, "8P") 514 | (255, "+P") |] 515 | 516 | let base64Tests = 517 | testList "Base64" [ 518 | testCase "Base64 encode test out of range encoding" <| fun () -> 519 | Expect.throws (fun _ -> Base64.base64Encode -1 |> ignore) "Should throw" 520 | 521 | testCase "Base64 encode test out of range encoding#2" <| fun () -> 522 | Expect.throws (fun _ -> Base64.base64Encode 64 |> ignore) "Should throw#2" 523 | 524 | 525 | testCase "test normal encoding and decoding" <| fun () -> 526 | for i in [ 0 .. 63 ] do 527 | Expect.pass (Base64.base64Encode i |> ignore) 528 | 529 | testCase "test normal encoding and decoding for VLQ" <| fun () -> 530 | for (num, str) in vlqs do 531 | let s = Base64Vlq.Encode num 532 | Expect.equal str s "Decoding/encoding equal" 533 | ] 534 | 535 | -------------------------------------------------------------------------------- /Tests.Fable/SourceMapGenerator.fs: -------------------------------------------------------------------------------- 1 | module Tests_Fable.SourceMapGenerator 2 | open Fable.Mocha 3 | open Fable.SimpleJson 4 | open SourceMapSharp 5 | open SourceMapSharp.Util 6 | open Tests_Fable.Util 7 | let testMap: SourceGeneratorJSON = { 8 | version=3 9 | file="min.js"|>Some 10 | sources= seq {"one.js";"two.js"} 11 | names=seq {"bar";"baz";"n"} 12 | mappings="CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA" 13 | sourcesContent=None 14 | sourceRoot="/the/root"|>Some 15 | } 16 | let sourceMapGeneratorTests = 17 | 18 | testList "SourceGenerator" [ 19 | 20 | testCase "test some simple stuff" <| fun () -> 21 | let map = SourceMapGenerator(file="foo.js",sourceRoot=".").toJSON() 22 | Expect.isTrue map.file.IsSome "map file is some" 23 | Expect.isTrue map.sourceRoot.IsSome "sourceRoot is some" 24 | let map = SourceMapGenerator().toJSON() 25 | Expect.isTrue map.file.IsNone "map file is none" 26 | Expect.isTrue map.sourceRoot.IsNone "map sourceroot is none" 27 | 28 | 29 | testCase "test JSON serialization 1" <| fun () -> 30 | let map = SourceMapGenerator(file="foo.js",sourceRoot=".") 31 | let s = map.ToString() 32 | Expect.isNotNull s "s is not null" 33 | 34 | 35 | testCase "test JSON serialization 2" <| fun () -> 36 | let s = Json.serialize testMap 37 | Expect.equal """{"version": 3, "sources": ["one.js", "two.js"], "names": ["bar", "baz", "n"], "mappings": "CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA", "file": "min.js", "sourcesContent": null, "sourceRoot": "/the/root"}""" s "json ser test 2" 38 | 39 | 40 | testCase "test adding mappings (case 1)" <| fun () -> 41 | let map = SourceMapGenerator(file="generated-foo.js",sourceRoot=".") 42 | let generated: MappingIndex = {line=1;column=1} 43 | Expect.pass (map.AddMapping(generated)) 44 | 45 | 46 | testCase "test adding mappings (case 2)" <| fun () -> 47 | let map = SourceMapGenerator(file="generated-foo.js",sourceRoot=".") 48 | let generated: MappingIndex = {line=1;column=1} 49 | let original: MappingIndex = {line=1;column=1} 50 | Expect.pass (map.AddMapping(generated,original,"bar.js")) 51 | 52 | 53 | testCase "test adding mappings (case 3)" <| fun () -> 54 | let map = SourceMapGenerator(file="generated-foo.js",sourceRoot=".") 55 | let generated: MappingIndex = {line=1;column=1} 56 | let original: MappingIndex = {line=1;column=1} 57 | Expect.pass (map.AddMapping(generated,original,"bar.js","someToken")) 58 | 59 | 60 | testCase "test adding mappings (invalid)" <| fun () -> 61 | let map = SourceMapGenerator(file="generated-foo.js",sourceRoot=".") 62 | let generated: MappingIndex = {line=1;column=1} 63 | let original: MappingIndex = {line=1;column=1} 64 | Expect.throws (fun _ -> map.AddMapping(generated,original)) "invalid mappings" 65 | 66 | 67 | testCase "test adding mappings with skipValidation" <| fun () -> 68 | let map = SourceMapGenerator(skipValidation=true, file="generated-foo.js",sourceRoot=".") 69 | let generated: MappingIndex = {line=1;column=1} 70 | let original: MappingIndex = {line=1;column=1} 71 | Expect.pass (map.AddMapping(generated,original)) 72 | 73 | 74 | testCase "test that the correct mappings are being generated" <| fun () -> 75 | let map = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 76 | let generated: MappingIndex = { line= 1; column= 1 } 77 | let original: MappingIndex = { line= 1; column= 1 } 78 | map.AddMapping(generated, original, "one.js") 79 | 80 | let generated: MappingIndex = { line= 1; column= 5 } 81 | let original: MappingIndex = { line= 1; column= 5 } 82 | map.AddMapping(generated, original, "one.js") 83 | 84 | let generated: MappingIndex = { line= 1; column= 9 } 85 | let original: MappingIndex = { line= 1; column= 11 } 86 | map.AddMapping(generated, original, "one.js") 87 | 88 | let generated: MappingIndex = { line= 1; column= 18 } 89 | let original: MappingIndex = { line= 1; column= 21 } 90 | map.AddMapping(generated, original, "one.js", "bar") 91 | 92 | let generated: MappingIndex = { line= 1; column= 21 } 93 | let original: MappingIndex = { line= 2; column= 3 } 94 | map.AddMapping(generated, original, "one.js") 95 | 96 | let generated: MappingIndex = { line= 1; column= 28 } 97 | let original: MappingIndex = { line= 2; column= 10 } 98 | map.AddMapping(generated, original, "one.js", "baz") 99 | 100 | let generated: MappingIndex = { line= 1; column= 32 } 101 | let original: MappingIndex = { line= 2; column= 14 } 102 | map.AddMapping(generated, original, "one.js", "bar") 103 | 104 | let generated: MappingIndex = { line= 2; column= 1 } 105 | let original: MappingIndex = { line= 1; column= 1 } 106 | map.AddMapping(generated, original, "two.js") 107 | 108 | let generated: MappingIndex = { line= 2; column= 5 } 109 | let original: MappingIndex = { line= 1; column= 5 } 110 | map.AddMapping(generated, original, "two.js") 111 | 112 | let generated: MappingIndex = { line= 2; column= 9 } 113 | let original: MappingIndex = { line= 1; column= 11 } 114 | map.AddMapping(generated, original, "two.js") 115 | 116 | let generated: MappingIndex = { line= 2; column= 18 } 117 | let original: MappingIndex = { line= 1; column= 21 } 118 | map.AddMapping(generated, original, "two.js", "n") 119 | 120 | let generated: MappingIndex = { line= 2; column= 21 } 121 | let original: MappingIndex = { line= 2; column= 3 } 122 | map.AddMapping(generated, original, "two.js") 123 | 124 | let generated: MappingIndex = { line= 2; column= 28 } 125 | let original: MappingIndex = { line= 2; column= 10 } 126 | map.AddMapping(generated, original, "two.js", "n") 127 | 128 | TestUtils.assertEqualSourceMaps(map,testMap) 129 | 130 | 131 | 132 | testCase "test that adding a mapping with an empty string name does not break generation" <| fun () -> 133 | let map = SourceMapGenerator(file="generated-foo.js",sourceRoot=".") 134 | let generated: MappingIndex = {line=1;column=1} 135 | let original: MappingIndex = {line=1;column=1} 136 | Expect.pass (map.AddMapping(generated,original, source="bar.js",name="")) 137 | Expect.pass (map.toJSON() |> ignore) 138 | 139 | 140 | testCase "test that source content can be set" <| fun () -> 141 | let map = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 142 | let generated: MappingIndex = { line= 1; column= 1 } 143 | let original: MappingIndex = { line= 1; column= 1 } 144 | map.AddMapping(generated, original, "one.js") 145 | let generated: MappingIndex = { line= 2; column= 1 } 146 | let original: MappingIndex = { line= 1; column= 1 } 147 | map.AddMapping(generated, original, "two.js") 148 | map.SetSourceContent("one.js",Some "one file content") 149 | let j = map.toJSON() 150 | let _src = j.sources |> Array.ofSeq 151 | let _srcC = j.sourcesContent.Value |> Array.ofSeq 152 | Expect.isTrue (_src.[0] = "one.js") "src[0] is one" 153 | Expect.isTrue (_src.[1] = "two.js") "src[1] is two" 154 | Expect.isTrue (_srcC.[0].Value = "one file content") "src[0] is some" 155 | Expect.isTrue (_srcC.[1].IsNone) "src[1] is none" 156 | 157 | testCase "test sorting with duplicate generated mappings" <| fun () -> 158 | let map = SourceMapGenerator(file="test.js") 159 | let generated1: MappingIndex = { line= 3; column= 0 } 160 | let original1: MappingIndex = { line= 2; column= 0 } 161 | map.AddMapping(generated1, original1, "a.js") 162 | 163 | let generated2: MappingIndex = { line= 2; column= 0 } 164 | map.AddMapping(generated2) 165 | 166 | let generated3: MappingIndex = { line= 2; column= 0 } 167 | map.AddMapping(generated3) 168 | 169 | let generated4: MappingIndex = { line= 1; column= 0 } 170 | let original4: MappingIndex = { line= 1; column= 0 } 171 | map.AddMapping(generated4, original4, "a.js") 172 | let expected = { 173 | version=3 174 | file="test.js"|>Some 175 | sources= seq {"a.js"} 176 | names= Seq.empty 177 | mappings="AAAA;A;AACA" 178 | sourcesContent=None 179 | sourceRoot=None 180 | } 181 | TestUtils.assertEqualSourceMaps(map,expected) 182 | 183 | testCase "test ignore duplicate mappings." <| fun () -> 184 | let map1 = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 185 | let map2 = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 186 | 187 | let nullMapping1: MappingIndex = { line= 1; column= 0 } 188 | let nullMapping2: MappingIndex = { line= 2; column= 2 } 189 | 190 | map1.AddMapping(nullMapping1) 191 | map1.AddMapping(nullMapping1) 192 | 193 | map2.AddMapping(nullMapping1) 194 | 195 | TestUtils.assertEqualSourceMaps(map1,map2) 196 | 197 | map1.AddMapping(nullMapping2) 198 | map1.AddMapping(nullMapping1) 199 | 200 | map2.AddMapping(nullMapping2) 201 | 202 | TestUtils.assertEqualSourceMaps(map1,map2) 203 | 204 | let srcMapping1Generated: MappingIndex = { line= 1; column= 0 } 205 | let srcMapping1Original: MappingIndex = { line= 11; column= 0 } 206 | let srcMapping1Source = "srcMapping1.js" 207 | 208 | let srcMapping2Generated: MappingIndex = { line= 2; column= 2 } 209 | let srcMapping2Original: MappingIndex = { line= 11; column= 0 } 210 | let srcMapping2Source = "srcMapping2.js" 211 | 212 | let map1 = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 213 | let map2 = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 214 | 215 | map1.AddMapping(srcMapping1Generated,srcMapping1Original,srcMapping1Source) 216 | map1.AddMapping(srcMapping1Generated,srcMapping1Original,srcMapping1Source) 217 | 218 | map2.AddMapping(srcMapping1Generated,srcMapping1Original,srcMapping1Source) 219 | 220 | TestUtils.assertEqualSourceMaps(map1,map2) 221 | 222 | map1.AddMapping(srcMapping2Generated,srcMapping2Original,srcMapping2Source) 223 | map1.AddMapping(srcMapping1Generated,srcMapping1Original,srcMapping1Source) 224 | 225 | map2.AddMapping(srcMapping2Generated,srcMapping2Original,srcMapping2Source) 226 | 227 | TestUtils.assertEqualSourceMaps(map1,map2) 228 | 229 | 230 | let fullMapping1Generated: MappingIndex = { line= 1; column= 0 } 231 | let fullMapping1Original: MappingIndex = { line= 11; column= 0 } 232 | let fullMapping1Source = "fullMapping1.js" 233 | let fullMapping1Name = "fullMapping1" 234 | 235 | let fullMapping2Generated: MappingIndex = { line= 2; column= 2 } 236 | let fullMapping2Original: MappingIndex = { line= 11; column= 0 } 237 | let fullMapping2Source = "fullMapping2.js" 238 | let fullMapping2Name = "fullMapping2" 239 | 240 | let map1 = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 241 | let map2 = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 242 | 243 | map1.AddMapping(fullMapping1Generated,fullMapping1Original,fullMapping1Source,fullMapping1Name) 244 | map1.AddMapping(fullMapping1Generated,fullMapping1Original,fullMapping1Source,fullMapping1Name) 245 | 246 | map2.AddMapping(fullMapping1Generated,fullMapping1Original,fullMapping1Source,fullMapping1Name) 247 | 248 | TestUtils.assertEqualSourceMaps(map1,map2) 249 | 250 | map1.AddMapping(fullMapping2Generated,fullMapping2Original,fullMapping2Source,fullMapping2Name) 251 | map1.AddMapping(fullMapping1Generated,fullMapping1Original,fullMapping1Source,fullMapping1Name) 252 | 253 | map2.AddMapping(fullMapping2Generated,fullMapping2Original,fullMapping2Source,fullMapping2Name) 254 | TestUtils.assertEqualSourceMaps(map1,map2) 255 | 256 | 257 | 258 | testCase "test github issue #72, check for duplicate names or sources" <| fun () -> 259 | let map = SourceMapGenerator(file="test.js") 260 | let generated1: MappingIndex = { line= 1; column= 1 } 261 | let original1: MappingIndex = { line= 2; column= 2 } 262 | map.AddMapping(generated1, original1, "a.js", "foo") 263 | 264 | let generated2: MappingIndex = { line= 3; column= 3 } 265 | let original2: MappingIndex = { line= 4; column= 4 } 266 | map.AddMapping(generated2, original2, "a.js", "foo") 267 | 268 | let expected = { 269 | version=3 270 | file="test.js"|>Some 271 | sources= seq {"a.js"} 272 | names= seq {"foo"} 273 | mappings="CACEA;;GAEEA" 274 | sourcesContent=None 275 | sourceRoot=None 276 | } 277 | TestUtils.assertEqualSourceMaps(map,expected) 278 | 279 | 280 | testCase "test setting sourcesContent to null when already null" <| fun () -> 281 | let map = SourceMapGenerator(file="foo.js") 282 | Expect.pass (map.SetSourceContent("bar.js",None)) 283 | 284 | 285 | testCase "test numeric names #231" <| fun () -> 286 | let map = SourceMapGenerator() 287 | let generated: MappingIndex = {line=1;column=10} 288 | let original: MappingIndex = {line=1;column=10} 289 | // type safe names! can't pass number 290 | map.AddMapping(generated,original, source="a.js",name="8") 291 | 292 | let m = map.toJSON() 293 | Expect.equal (m.names |> Seq.length) 1 "m is of length 1" 294 | Expect.equal (m.names |> Seq.head) "8" "m head is 8" 295 | ] -------------------------------------------------------------------------------- /Tests.Fable/SourceNode.fs: -------------------------------------------------------------------------------- 1 | module Tests_Fable.SourceNode 2 | open Fable.Mocha 3 | open Fable.SimpleJson 4 | open SourceMapSharp 5 | open SourceMapSharp.Util 6 | open Tests_Fable.Util 7 | 8 | 9 | let sourceNodeTests = 10 | 11 | testList "SourceNode" [ 12 | 13 | testCase "test .add()" <| fun () -> 14 | let node = SourceNode() 15 | node.Add(SourceChunk.ChunkS "function noop() {}") |> ignore 16 | node.Add(SourceChunk.ChunkArrSN [|SourceNode()|]) |> ignore 17 | node.Add(SourceChunk.ChunkArrSN [|SourceNode(_chunks=[|SourceChunk.ChunkS "return 10;"|])|]) |> ignore 18 | node.Add(SourceChunk.ChunkArrS [|"function foo() {";"}"|]) |> ignore 19 | 20 | testCase "test .prepend()" <| fun () -> 21 | let node = SourceNode() 22 | let s = "function noop() {}" 23 | node.Prepend(SourceChunk.ChunkS s) |> ignore 24 | Expect.equal node.children.[0] (SourceNodeChild.S s) "node children[0] equals source node child s" 25 | Expect.equal node.children.Count 1 "node children count is 1" 26 | 27 | node.Prepend(SourceChunk.ChunkArrSN [|SourceNode()|]) |> ignore 28 | Expect.isTrue (match node.children.[0] with | SN _ -> true | S _ -> false) "node children[0] is SN" 29 | Expect.isTrue (match node.children.[1] with | SN _ -> false | S _ -> true) "node children[1] is S" 30 | Expect.isTrue (match node.children.[1] with | SN _ -> false | S ss -> s = ss) "node children [1] is ss" 31 | Expect.isTrue (node.children.Count = 2) "node children count is 2" 32 | 33 | node.Prepend( 34 | [|SourceChunk.ChunkS "function foo() {" 35 | SourceChunk.ChunkArrSN [|SourceNode(_chunks=[|SourceChunk.ChunkS "return 10;"|])|] 36 | SourceChunk.ChunkS "}" 37 | |]) |> ignore 38 | 39 | Expect.equal (node.children.[0].ToString()) "function foo() {" "node children 0 is foo" 40 | Expect.equal (node.children.[1].ToString()) "return 10;" "node children 1 is return 10" 41 | Expect.equal (node.children.[2].ToString()) "}" "node children 2 is }" 42 | Expect.equal (node.children.[3].ToString()) "" "node children 2 is blank" 43 | Expect.equal (node.children.[4].ToString()) "function noop() {}" "node children 4 is noop fn" 44 | Expect.isTrue (node.children.Count = 5) "node children count is 5" 45 | 46 | 47 | testCase "test .toString()" <| fun () -> 48 | let node = SourceNode(_chunks=[| 49 | SourceChunk.ChunkS "function foo() {" 50 | SourceChunk.ChunkArrSN [|SourceNode(_chunks=[|SourceChunk.ChunkS "return 10;"|])|] 51 | SourceChunk.ChunkS "}" 52 | |]) 53 | Expect.equal (node.ToString()) "function foo() {return 10;}" "node is function foo return 10" 54 | 55 | 56 | testCase "test .join()" <| fun () -> 57 | let node = SourceNode(_chunks=[| 58 | SourceChunk.ChunkS "a" 59 | SourceChunk.ChunkS "b" 60 | SourceChunk.ChunkS "c" 61 | SourceChunk.ChunkS "d" 62 | |]) 63 | Expect.equal ("a, b, c, d") (node.Join(", ").ToString()) "a b c d is equal to node chunks" 64 | 65 | 66 | testCase "test .walk()" <| fun () -> 67 | let node = SourceNode(_chunks=[| 68 | SourceChunk.ChunkS "(function () {\n" 69 | SourceChunk.ChunkS " " 70 | SourceChunk.ChunkArrSN [| 71 | SourceNode(_line=1,_column=0,_source="a.js", 72 | _chunks=[|SourceChunk.ChunkS "someCall()"|]) 73 | |] 74 | SourceChunk.ChunkS ";\n" 75 | SourceChunk.ChunkS " " 76 | SourceChunk.ChunkArrSN [| 77 | SourceNode(_line=2,_column=0,_source="b.js", 78 | _chunks=[|SourceChunk.ChunkS "if (foo) bar()"|]) 79 | |] 80 | SourceChunk.ChunkS ";\n" 81 | SourceChunk.ChunkS "}());" 82 | |]) 83 | 84 | let expected = [| 85 | {| str= "(function () {\n"; source= None; line= None; column= None |} 86 | {| str= " "; source= None; line= None; column= None |} 87 | {| str= "someCall()"; source= Some "a.js"; line= Some 1; column= Some 0 |} 88 | {| str= ";\n"; source= None; line= None; column= None |} 89 | {| str= " "; source= None; line= None; column= None |} 90 | {| str= "if (foo) bar()"; source= Some "b.js"; line= Some 2; column= Some 0 |} 91 | {| str= ";\n"; source= None; line= None; column= None |} 92 | {| str= "}());"; source= None; line= None; column= None |} 93 | |] 94 | 95 | 96 | let mutable i = 0 97 | node.Walk(fun chunk loc -> 98 | Expect.equal expected.[i].str chunk $"chunk str is equal for {i}" 99 | Expect.equal expected.[i].source loc.Source $"chunk source is equal for {i}" 100 | Expect.equal expected.[i].line loc.line $"chunk line is equal for {i}" 101 | Expect.equal expected.[i].column loc.column $"chunk column is equal for {i}" 102 | i <- i+1 103 | ) 104 | 105 | 106 | testCase "test .replaceRight()" <| fun () -> 107 | // Not nested 108 | let node = SourceNode(_chunks=[| 109 | SourceChunk.ChunkS "hello world" 110 | |]) 111 | node.ReplaceRight("world","universe") |> ignore 112 | Expect.equal "hello universe" (node.ToString()) "node replaceRight works" 113 | 114 | // Nested 115 | let node = SourceNode(_chunks=[| 116 | SourceChunk.ChunkArrSN [| 117 | SourceNode(_chunks=[| 118 | SourceChunk.ChunkS "hey sexy mama, " 119 | |]) 120 | SourceNode(_chunks=[| 121 | SourceChunk.ChunkS "want to kill all humans?" 122 | |]) 123 | |] 124 | |]) 125 | node.ReplaceRight("kill all humans", "watch Futurama") |> ignore 126 | Expect.equal "hey sexy mama, want to watch Futurama?" (node.ToString()) "replace right works for nested" 127 | 128 | 129 | 130 | testCase "test .toStringWithSourceMap()" <| fun () -> 131 | ["\n";"\r\n"] |> List.iter (fun nl -> 132 | let c1 = SourceChunk.ChunkS ("(function () {" + nl) 133 | let c2 = SourceChunk.ChunkS (" ") 134 | let c3 = SourceNode(_line=1,_column=0,_source="a.js", _name="originalCall", 135 | _chunks=[|SourceChunk.ChunkS "someCall"|]) 136 | let c4 = SourceNode(_line=1,_column=8,_source="a.js", 137 | _chunks=[|SourceChunk.ChunkS "()"|]) 138 | let c5 = SourceChunk.ChunkS (";" + nl) 139 | let c6 = SourceChunk.ChunkS (" ") 140 | let c7 = SourceNode(_line=2,_column=0,_source="b.js", 141 | _chunks=[|SourceChunk.ChunkS "if (foo) bar()"|]) 142 | let c8 = SourceChunk.ChunkS (";" + nl) 143 | let c9 = SourceChunk.ChunkS ("}());") 144 | let node = SourceNode(_chunks=[| 145 | c1 146 | c2 147 | SourceChunk.ChunkArrSN ([|c3;c4|]) 148 | c5 149 | c6 150 | SourceChunk.ChunkArrSN ([|c7|]) 151 | c8 152 | c9 153 | |]) 154 | let (code, resultMap) = node.ToStringWithSourceMap(file="foo.js") 155 | let expected = String.concat nl [ 156 | "(function () {" 157 | " someCall();" 158 | " if (foo) bar();" 159 | "}());" 160 | ] 161 | Expect.equal expected code "toStringWithSourceMap works" 162 | //todo: sourcemapconsumer part 163 | ) 164 | 165 | testCase "test .toStringWithSourceMap() with consecutive newlines" <| fun () -> 166 | ["\n";"\r\n"] |> List.iter (fun nl -> 167 | let c1 = SourceChunk.ChunkS ("/***/" + nl + nl) 168 | let c2 = SourceNode(_line=1,_column=0,_source="a.js", 169 | _chunks=[|SourceChunk.ChunkS ("'use strict';" + nl)|]) 170 | let c3 = SourceNode(_line=2,_column=0,_source="a.js", 171 | _chunks=[|SourceChunk.ChunkS "a();"|]) 172 | let input = SourceNode(_chunks=[| 173 | c1 174 | SourceChunk.ChunkArrSN ([|c2;c3|]) 175 | |]) 176 | let (code, inputMap) = input.ToStringWithSourceMap(file="foo.js") 177 | let expected = String.concat nl [ 178 | "/***/" 179 | "" 180 | "'use strict';" 181 | "a();" 182 | ] 183 | Expect.equal expected code "ToStringWithSourceMap works for many newlines" 184 | 185 | let map = SourceMapGenerator(file="foo.js") 186 | let generated: MappingIndex = { line= 3; column= 0 } 187 | let original: MappingIndex = { line= 1; column= 0 } 188 | map.AddMapping(generated, original, "a.js") 189 | let generated: MappingIndex = { line= 4; column= 0 } 190 | let original: MappingIndex = { line= 2; column= 0 } 191 | map.AddMapping(generated, original, "a.js") 192 | TestUtils.assertEqualSourceMaps(map,inputMap) 193 | ) 194 | 195 | 196 | testCase "test .toStringWithSourceMap() merging duplicate mappings" <| fun () -> 197 | ["\n";"\r\n"] |> List.iter (fun nl -> 198 | let c1 = SourceNode(_line=1,_column=0,_source="a.js", _chunks=[|SourceChunk.ChunkS ("(function")|]) 199 | let c2 = SourceNode(_line=1,_column=0,_source="a.js",_chunks=[|SourceChunk.ChunkS ("() {" + nl)|]) 200 | let c3 = SourceChunk.ChunkS (" ") 201 | let c4 = SourceNode(_line=1,_column=0,_source="a.js",_chunks=[|SourceChunk.ChunkS ("var Test = ")|]) 202 | let c5 = SourceNode(_line=1,_column=0,_source="b.js",_chunks=[|SourceChunk.ChunkS ("{};" + nl)|]) 203 | let c6 = SourceNode(_line=2,_column=0,_source="b.js",_chunks=[|SourceChunk.ChunkS ("Test")|]) 204 | let c7 = SourceNode(_line=2,_column=0,_source="b.js",_name="A",_chunks=[|SourceChunk.ChunkS (".A")|]) 205 | let c8 = SourceNode(_line=2,_column=20,_source="b.js",_name="A",_chunks=[|SourceChunk.ChunkS (" = { value: ")|]) 206 | let c9 = SourceChunk.ChunkS ("1234") 207 | let c10 = SourceNode(_line=2,_column=40,_source="b.js",_name="A",_chunks=[|SourceChunk.ChunkS (" };" + nl)|]) 208 | let c11 = SourceChunk.ChunkS ("}());" + nl) 209 | let c12 = SourceChunk.ChunkS ("/* Generated Source */") 210 | let input = SourceNode(_chunks=[| 211 | SourceChunk.ChunkArrSN ([|c1;c2|]) 212 | c3 213 | SourceChunk.ChunkArrSN ([|c4;c5;c6;c7;c8|]) 214 | c9 215 | SourceChunk.ChunkArrSN ([|c10|]) 216 | c11 217 | c12 218 | |]) 219 | let (code, inputMap) = input.ToStringWithSourceMap(file="foo.js") 220 | let expected = String.concat nl [ 221 | "(function() {" 222 | " var Test = {};" 223 | "Test.A = { value: 1234 };" 224 | "}());" 225 | "/* Generated Source */" ] 226 | Expect.equal expected code "ToStringWithSourceMap with duplicate maps works" 227 | 228 | let map = SourceMapGenerator(file="foo.js") 229 | let generated: MappingIndex = { line= 1; column= 0 } 230 | let original: MappingIndex = { line= 1; column= 0 } 231 | map.AddMapping(generated, original, "a.js") 232 | 233 | // Here is no need for a empty mapping, 234 | // because mappings ends at eol 235 | let generated: MappingIndex = { line= 2; column= 2 } 236 | let original: MappingIndex = { line= 1; column= 0 } 237 | map.AddMapping(generated, original, "a.js") 238 | 239 | let generated: MappingIndex = { line= 2; column= 13 } 240 | let original: MappingIndex = { line= 1; column= 0 } 241 | map.AddMapping(generated, original, "b.js") 242 | 243 | 244 | let generated: MappingIndex = { line= 3; column= 0 } 245 | let original: MappingIndex = { line= 2; column= 0 } 246 | map.AddMapping(generated, original, "b.js") 247 | 248 | let generated: MappingIndex = { line= 3; column= 4 } 249 | let original: MappingIndex = { line= 2; column= 0 } 250 | map.AddMapping(generated, original, "b.js", name="A") 251 | 252 | let generated: MappingIndex = { line= 3; column= 6 } 253 | let original: MappingIndex = { line= 2; column= 20 } 254 | map.AddMapping(generated, original, "b.js", name="A") 255 | 256 | // This empty mapping is required, 257 | // because there is a hole in the middle of the line 258 | let generated: MappingIndex = { line= 3; column= 18 } 259 | map.AddMapping(generated) 260 | 261 | let generated: MappingIndex = { line= 3; column= 22 } 262 | let original: MappingIndex = { line= 2; column= 40 } 263 | map.AddMapping(generated, original, "b.js", name="A") 264 | // Here is no need for a empty mapping, 265 | // because mappings ends at eol 266 | TestUtils.assertEqualSourceMaps(map,inputMap) 267 | ) 268 | 269 | 270 | 271 | testCase "test .toStringWithSourceMap() multi-line SourceNodes" <| fun () -> 272 | ["\n";"\r\n"] |> List.iter (fun nl -> 273 | let c1 = SourceNode(_line=1,_column=0,_source="a.js", 274 | _chunks=[|SourceChunk.ChunkS ("(function() {" + nl + "var nextLine = 1;" + nl + "anotherLine();" + nl)|]) 275 | let c2 = SourceNode(_line=2,_column=2,_source="b.js",_chunks=[|SourceChunk.ChunkS ("Test.call(this, 123);" + nl)|]) 276 | let c3 = SourceNode(_line=2,_column=2,_source="b.js",_chunks=[|SourceChunk.ChunkS ("this['stuff'] = 'v';" + nl)|]) 277 | let c4 = SourceNode(_line=2,_column=2,_source="b.js",_chunks=[|SourceChunk.ChunkS ("anotherLine();" + nl)|]) 278 | let c5 = SourceChunk.ChunkS ("/*" + nl + "Generated" + nl + "Source" + nl + "*/" + nl) 279 | let c6 = SourceNode(_line=3,_column=4,_source="c.js",_chunks=[|SourceChunk.ChunkS ("anotherLine();" + nl)|]) 280 | let c7 = SourceChunk.ChunkS ("/*" + nl + "Generated" + nl + "Source" + nl + "*/") 281 | 282 | let input = SourceNode(_chunks=[| 283 | SourceChunk.ChunkArrSN ([|c1;c2;c3;c4|]) 284 | c5 285 | SourceChunk.ChunkArrSN ([|c6|]) 286 | c7 287 | |]) 288 | let (code, inputMap) = input.ToStringWithSourceMap(file="foo.js") 289 | let expected = String.concat nl [ 290 | "(function() {" 291 | "var nextLine = 1;" 292 | "anotherLine();" 293 | "Test.call(this, 123);" 294 | "this['stuff'] = 'v';" 295 | "anotherLine();" 296 | "/*" 297 | "Generated" 298 | "Source" 299 | "*/" 300 | "anotherLine();" 301 | "/*" 302 | "Generated" 303 | "Source" 304 | "*/" ] 305 | Expect.equal expected code "ToStringWithSourceMap works with multiline sourcemaps" 306 | 307 | let map = SourceMapGenerator(file="foo.js") 308 | let generated: MappingIndex = { line= 1; column= 0 } 309 | let original: MappingIndex = { line= 1; column= 0 } 310 | map.AddMapping(generated, original, "a.js") 311 | 312 | let generated: MappingIndex = { line= 2; column= 0 } 313 | let original: MappingIndex = { line= 1; column= 0 } 314 | map.AddMapping(generated, original, "a.js") 315 | 316 | let generated: MappingIndex = { line= 3; column= 0 } 317 | let original: MappingIndex = { line= 1; column= 0 } 318 | map.AddMapping(generated, original, "a.js") 319 | 320 | let generated: MappingIndex = { line= 4; column= 0 } 321 | let original: MappingIndex = { line= 2; column= 2 } 322 | map.AddMapping(generated, original, "b.js") 323 | 324 | let generated: MappingIndex = { line= 5; column= 0 } 325 | let original: MappingIndex = { line= 2; column= 2 } 326 | map.AddMapping(generated, original, "b.js") 327 | 328 | let generated: MappingIndex = { line= 6; column= 0 } 329 | let original: MappingIndex = { line= 2; column= 2 } 330 | map.AddMapping(generated, original, "b.js") 331 | 332 | let generated: MappingIndex = { line= 11; column= 0 } 333 | let original: MappingIndex = { line= 3; column= 4 } 334 | map.AddMapping(generated, original, "c.js") 335 | 336 | TestUtils.assertEqualSourceMaps(map,inputMap) 337 | 338 | ) 339 | 340 | 341 | testCase "test .toStringWithSourceMap() with empty string" <| fun () -> 342 | let node = SourceNode(_line=1,_column=0,_source="empty.js",_chunks=[|SourceChunk.ChunkS ""|]) 343 | let (code, _) = node.ToStringWithSourceMap(file="") 344 | Expect.equal code "" "toStringWithSourceMap works for empty string" 345 | 346 | 347 | testCase "test setSourceContent with toStringWithSourceMap" <| fun () -> 348 | let aNode = SourceNode(_line=1,_column=1,_source="a.js",_chunks=[|SourceChunk.ChunkS "a"|]) 349 | aNode.SetSourceContent("a.js","someContent") 350 | let node = SourceNode(_chunks=[| 351 | SourceChunk.ChunkS "(function () {\n" 352 | SourceChunk.ChunkS " " 353 | SourceChunk.ChunkArrSN [| aNode |] 354 | SourceChunk.ChunkS " " 355 | SourceChunk.ChunkArrSN [| 356 | SourceNode(_line=1,_column=1,_source="b.js",_chunks=[|SourceChunk.ChunkS "b"|]) 357 | |] 358 | SourceChunk.ChunkS "}());" 359 | |]) 360 | node.SetSourceContent("b.js","otherContent") 361 | let (_, map) = node.ToStringWithSourceMap(file="foo.js") 362 | // Expect.pass (fun () -> map |> ignore) //dummy assert 363 | 364 | Expect.equal (map._sources.Size()) 2 "sources is 2" 365 | Expect.equal (map._sources.At(0).Value) "a.js" "first is a.js" 366 | Expect.equal (map._sources.At(1).Value) "b.js" "second is b.js" 367 | Expect.equal map._sourcesContents.Count 2 "sources count is 2" 368 | let sc = map._sourcesContents |> Seq.map (fun kvp -> kvp.Value) |> Array.ofSeq 369 | Expect.equal sc.[0] "someContent" "some content in a" 370 | Expect.equal sc.[1] "otherContent" "other content in b" 371 | 372 | 373 | testCase "test walkSourceContents" <| fun () -> 374 | let aNode = SourceNode(_line=1,_column=0,_source="a.js",_chunks=[|SourceChunk.ChunkS "a"|]) 375 | aNode.SetSourceContent("a.js","someContent") 376 | let node = SourceNode(_chunks=[| 377 | SourceChunk.ChunkS "(function () {\n" 378 | SourceChunk.ChunkS " " 379 | SourceChunk.ChunkArrSN [| aNode |] 380 | SourceChunk.ChunkS " " 381 | SourceChunk.ChunkArrSN [| 382 | SourceNode(_line=1,_column=1,_source="b.js",_chunks=[|SourceChunk.ChunkS "b"|]) 383 | |] 384 | SourceChunk.ChunkS "}());" 385 | |]) 386 | node.SetSourceContent("b.js","otherContent") 387 | let results = ResizeArray<_>() 388 | node.WalkSourceContents(results.Add) 389 | Expect.equal results.Count 2 "results count is 2" 390 | Expect.equal (fst results.[0]) "a.js" "results.1.0 is correct" 391 | Expect.equal (snd results.[0]) "someContent" "results.2.0 is correct" 392 | Expect.equal (fst results.[1]) "b.js" "results.1.1 is correct" 393 | Expect.equal (snd results.[1]) "otherContent" "results.2.1 is correct" 394 | ] -------------------------------------------------------------------------------- /Tests.Fable/Tests.Fable.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netstandard2.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Tests.Fable/Tests.fs: -------------------------------------------------------------------------------- 1 | 2 | open Fable.Mocha 3 | 4 | let _ = 5 | [| 6 | Tests_Fable.Util.utilTests 7 | Tests_Fable.Base64.base64Tests 8 | Tests_Fable.ArraySet.arraySetTests 9 | Tests_Fable.SourceMapGenerator.sourceMapGeneratorTests 10 | Tests_Fable.SourceNode.sourceNodeTests 11 | |] |> Array.map Mocha.runTests 12 | -------------------------------------------------------------------------------- /Tests.Fable/Util.fs: -------------------------------------------------------------------------------- 1 | module Tests_Fable.Util 2 | 3 | open Fable.Mocha 4 | open SourceMapSharp 5 | open SourceMapSharp.Util 6 | open Fable.SimpleJson 7 | type TestUtils = 8 | static member assertEqualSourceMaps(s1:SourceMapGenerator,s2:SourceMapGenerator) = 9 | let serialized1 = Json.serialize (s1.toJSON()) 10 | let serialized2 = Json.serialize (s2.toJSON()) 11 | Expect.equal serialized1 serialized2 "sourcemaps not equal" 12 | 13 | static member assertEqualSourceMaps(s1:SourceMapGenerator,s2:SourceGeneratorJSON) = 14 | let serialized2 = Json.serialize s2 15 | let serialized1 = Json.serialize (s1.toJSON()) 16 | Expect.equal serialized1 serialized2 "source map json not equal" 17 | 18 | let utilTests = 19 | testList "Util" [ 20 | testCase "test relative()" <| fun () -> 21 | 22 | Expect.equal (Util.getRelativePath ("/the/root", "/the/root/one.js")) "one.js" "relative path not equal" 23 | Expect.equal (Util.getRelativePath ("http://the/root", "http://the/root/one.js")) "one.js" "relative path not equal" 24 | Expect.equal (Util.getRelativePath ("/the/root", "/the/rootone.js")) "../rootone.js" "relative path not equal" 25 | Expect.equal (Util.getRelativePath ("http://the/root", "http://the/rootone.js")) "../rootone.js" "relative path not equal" 26 | Expect.equal (Util.getRelativePath ("/the/root", "/therootone.js")) "../../therootone.js" "relative path not equal" 27 | Expect.equal (Util.getRelativePath ("http://the/root", "/therootone.js")) "/therootone.js" "relative path not equal" 28 | Expect.equal (Util.getRelativePath ("", "/the/root/one.js")) "/the/root/one.js" "relative path not equal" 29 | Expect.equal (Util.getRelativePath (".", "/the/root/one.js")) "/the/root/one.js" "relative path not equal" 30 | Expect.equal (Util.getRelativePath ("", "the/root/one.js")) "the/root/one.js" "relative path not equal" 31 | Expect.equal (Util.getRelativePath (".", "the/root/one.js")) "the/root/one.js" "relative path not equal" 32 | Expect.equal (Util.getRelativePath ("/", "/the/root/one.js")) "the/root/one.js" "relative path not equal" 33 | Expect.equal (Util.getRelativePath ("/", "the/root/one.js")) "the/root/one.js" "relative path not equal" 34 | ] -------------------------------------------------------------------------------- /Tests/ArraySet.fs: -------------------------------------------------------------------------------- 1 | module Tests.ArraySet 2 | open SourceMapSharp 3 | open Xunit 4 | 5 | module ArraySetTests = 6 | 7 | let makeTestSet () = 8 | let set = ArraySet() 9 | 10 | for i in [ 0 .. 99 ] do 11 | set.Add(string i, false) 12 | 13 | set 14 | 15 | [] 16 | let ``test .has() membership`` () = 17 | let set = makeTestSet () 18 | 19 | for i in [ 0 .. 99 ] do 20 | Assert.True(set.Has(string i)) 21 | 22 | [] 23 | let ``test .indexOf() elements`` () = 24 | let set = makeTestSet () 25 | 26 | for i in [ 0 .. 99 ] do 27 | let a = set.indexOf (string i) 28 | Assert.StrictEqual(a, Some i) 29 | 30 | [] 31 | let ``test .at() indexing`` () = 32 | let set = makeTestSet () 33 | 34 | for i in [ 0 .. 99 ] do 35 | let a = set.At(i) 36 | Assert.StrictEqual(a, Some(string i)) 37 | 38 | [] 39 | let ``test creating from an array`` () = 40 | let set = 41 | ArraySet.fromArray 42 | ([| "foo" 43 | "bar" 44 | "baz" 45 | "quux" 46 | "hasOwnProperty" |], 47 | false) 48 | Assert.True(set.Has("foo")) 49 | Assert.True(set.Has("bar")) 50 | Assert.True(set.Has("baz")) 51 | Assert.True(set.Has("quux")) 52 | Assert.True(set.Has("hasOwnProperty")) 53 | 54 | Assert.StrictEqual(set.indexOf("foo"), Some 0) 55 | Assert.StrictEqual(set.indexOf("bar"), Some 1) 56 | Assert.StrictEqual(set.indexOf("baz"), Some 2) 57 | Assert.StrictEqual(set.indexOf("quux"), Some 3) 58 | 59 | Assert.StrictEqual(set.At(0), Some "foo") 60 | Assert.StrictEqual(set.At(1), Some "bar") 61 | Assert.StrictEqual(set.At(2), Some "baz") 62 | Assert.StrictEqual(set.At(3), Some "quux") 63 | 64 | 65 | [] 66 | let ``test that you can add __proto__; see github issue #30`` () = 67 | let set = ArraySet () 68 | set.Add("__proto__",false) 69 | Assert.True(set.Has("__proto__")) 70 | Assert.StrictEqual(set.indexOf("__proto__"), Some 0) 71 | Assert.StrictEqual(set.At(0), Some "__proto__") 72 | 73 | 74 | [] 75 | let ``test .fromArray() with duplicates`` () = 76 | let set = ArraySet.fromArray ([| "foo";"foo"|],false) 77 | 78 | Assert.True(set.Has("foo")) 79 | Assert.StrictEqual(set.At(0), Some "foo") 80 | Assert.StrictEqual(set.indexOf("foo"), Some 0) 81 | Assert.StrictEqual(set.ToArray().Count, 1) 82 | 83 | let set = ArraySet.fromArray ([| "foo";"foo"|],true) 84 | 85 | Assert.True(set.Has("foo")) 86 | Assert.StrictEqual(set.At(0), Some "foo") 87 | Assert.StrictEqual(set.At(1), Some "foo") 88 | Assert.StrictEqual(set.indexOf("foo"), Some 0) 89 | Assert.StrictEqual(set.ToArray().Count, 2) 90 | 91 | [] 92 | let ``test .add() with duplicates`` () = 93 | 94 | let set = ArraySet() 95 | set.Add("foo",false) 96 | set.Add("foo",false) 97 | 98 | Assert.True(set.Has("foo")) 99 | Assert.StrictEqual(set.At(0), Some "foo") 100 | Assert.StrictEqual(set.indexOf("foo"), Some 0) 101 | Assert.StrictEqual(set.ToArray().Count, 1) 102 | 103 | set.Add("foo",true) 104 | 105 | Assert.True(set.Has("foo")) 106 | Assert.StrictEqual(set.At(0), Some "foo") 107 | Assert.StrictEqual(set.At(1), Some "foo") 108 | Assert.StrictEqual(set.indexOf("foo"), Some 0) 109 | Assert.StrictEqual(set.ToArray().Count, 2) 110 | 111 | [] 112 | let ``test .size()`` () = 113 | let set = ArraySet () 114 | set.Add("foo",false) 115 | set.Add("bar",false) 116 | set.Add("baz",false) 117 | Assert.StrictEqual(set.Size(), 3) 118 | 119 | [] 120 | let ``test .size() with disallowed duplicates`` () = 121 | let set = ArraySet () 122 | set.Add("foo",false) 123 | set.Add("foo",false) 124 | set.Add("bar",false) 125 | set.Add("bar",false) 126 | set.Add("baz",false) 127 | set.Add("baz",false) 128 | Assert.StrictEqual(set.Size(), 3) 129 | 130 | 131 | [] 132 | let ``test .size() with allowed duplicates`` () = 133 | let set = ArraySet () 134 | set.Add("foo",false) 135 | set.Add("foo",true) 136 | set.Add("bar",false) 137 | set.Add("bar",true) 138 | set.Add("baz",false) 139 | set.Add("baz",true) 140 | Assert.StrictEqual(set.Size(), 3) 141 | -------------------------------------------------------------------------------- /Tests/Base64.fs: -------------------------------------------------------------------------------- 1 | module Tests.Base64 2 | open System 3 | open SourceMapSharp 4 | open Xunit 5 | 6 | module Base64Tests = 7 | let vlqs = 8 | [| (-255, "/P") 9 | (-254, "9P") 10 | (-253, "7P") 11 | (-252, "5P") 12 | (-251, "3P") 13 | (-250, "1P") 14 | (-249, "zP") 15 | (-248, "xP") 16 | (-247, "vP") 17 | (-246, "tP") 18 | (-245, "rP") 19 | (-244, "pP") 20 | (-243, "nP") 21 | (-242, "lP") 22 | (-241, "jP") 23 | (-240, "hP") 24 | (-239, "/O") 25 | (-238, "9O") 26 | (-237, "7O") 27 | (-236, "5O") 28 | (-235, "3O") 29 | (-234, "1O") 30 | (-233, "zO") 31 | (-232, "xO") 32 | (-231, "vO") 33 | (-230, "tO") 34 | (-229, "rO") 35 | (-228, "pO") 36 | (-227, "nO") 37 | (-226, "lO") 38 | (-225, "jO") 39 | (-224, "hO") 40 | (-223, "/N") 41 | (-222, "9N") 42 | (-221, "7N") 43 | (-220, "5N") 44 | (-219, "3N") 45 | (-218, "1N") 46 | (-217, "zN") 47 | (-216, "xN") 48 | (-215, "vN") 49 | (-214, "tN") 50 | (-213, "rN") 51 | (-212, "pN") 52 | (-211, "nN") 53 | (-210, "lN") 54 | (-209, "jN") 55 | (-208, "hN") 56 | (-207, "/M") 57 | (-206, "9M") 58 | (-205, "7M") 59 | (-204, "5M") 60 | (-203, "3M") 61 | (-202, "1M") 62 | (-201, "zM") 63 | (-200, "xM") 64 | (-199, "vM") 65 | (-198, "tM") 66 | (-197, "rM") 67 | (-196, "pM") 68 | (-195, "nM") 69 | (-194, "lM") 70 | (-193, "jM") 71 | (-192, "hM") 72 | (-191, "/L") 73 | (-190, "9L") 74 | (-189, "7L") 75 | (-188, "5L") 76 | (-187, "3L") 77 | (-186, "1L") 78 | (-185, "zL") 79 | (-184, "xL") 80 | (-183, "vL") 81 | (-182, "tL") 82 | (-181, "rL") 83 | (-180, "pL") 84 | (-179, "nL") 85 | (-178, "lL") 86 | (-177, "jL") 87 | (-176, "hL") 88 | (-175, "/K") 89 | (-174, "9K") 90 | (-173, "7K") 91 | (-172, "5K") 92 | (-171, "3K") 93 | (-170, "1K") 94 | (-169, "zK") 95 | (-168, "xK") 96 | (-167, "vK") 97 | (-166, "tK") 98 | (-165, "rK") 99 | (-164, "pK") 100 | (-163, "nK") 101 | (-162, "lK") 102 | (-161, "jK") 103 | (-160, "hK") 104 | (-159, "/J") 105 | (-158, "9J") 106 | (-157, "7J") 107 | (-156, "5J") 108 | (-155, "3J") 109 | (-154, "1J") 110 | (-153, "zJ") 111 | (-152, "xJ") 112 | (-151, "vJ") 113 | (-150, "tJ") 114 | (-149, "rJ") 115 | (-148, "pJ") 116 | (-147, "nJ") 117 | (-146, "lJ") 118 | (-145, "jJ") 119 | (-144, "hJ") 120 | (-143, "/I") 121 | (-142, "9I") 122 | (-141, "7I") 123 | (-140, "5I") 124 | (-139, "3I") 125 | (-138, "1I") 126 | (-137, "zI") 127 | (-136, "xI") 128 | (-135, "vI") 129 | (-134, "tI") 130 | (-133, "rI") 131 | (-132, "pI") 132 | (-131, "nI") 133 | (-130, "lI") 134 | (-129, "jI") 135 | (-128, "hI") 136 | (-127, "/H") 137 | (-126, "9H") 138 | (-125, "7H") 139 | (-124, "5H") 140 | (-123, "3H") 141 | (-122, "1H") 142 | (-121, "zH") 143 | (-120, "xH") 144 | (-119, "vH") 145 | (-118, "tH") 146 | (-117, "rH") 147 | (-116, "pH") 148 | (-115, "nH") 149 | (-114, "lH") 150 | (-113, "jH") 151 | (-112, "hH") 152 | (-111, "/G") 153 | (-110, "9G") 154 | (-109, "7G") 155 | (-108, "5G") 156 | (-107, "3G") 157 | (-106, "1G") 158 | (-105, "zG") 159 | (-104, "xG") 160 | (-103, "vG") 161 | (-102, "tG") 162 | (-101, "rG") 163 | (-100, "pG") 164 | (-99, "nG") 165 | (-98, "lG") 166 | (-97, "jG") 167 | (-96, "hG") 168 | (-95, "/F") 169 | (-94, "9F") 170 | (-93, "7F") 171 | (-92, "5F") 172 | (-91, "3F") 173 | (-90, "1F") 174 | (-89, "zF") 175 | (-88, "xF") 176 | (-87, "vF") 177 | (-86, "tF") 178 | (-85, "rF") 179 | (-84, "pF") 180 | (-83, "nF") 181 | (-82, "lF") 182 | (-81, "jF") 183 | (-80, "hF") 184 | (-79, "/E") 185 | (-78, "9E") 186 | (-77, "7E") 187 | (-76, "5E") 188 | (-75, "3E") 189 | (-74, "1E") 190 | (-73, "zE") 191 | (-72, "xE") 192 | (-71, "vE") 193 | (-70, "tE") 194 | (-69, "rE") 195 | (-68, "pE") 196 | (-67, "nE") 197 | (-66, "lE") 198 | (-65, "jE") 199 | (-64, "hE") 200 | (-63, "/D") 201 | (-62, "9D") 202 | (-61, "7D") 203 | (-60, "5D") 204 | (-59, "3D") 205 | (-58, "1D") 206 | (-57, "zD") 207 | (-56, "xD") 208 | (-55, "vD") 209 | (-54, "tD") 210 | (-53, "rD") 211 | (-52, "pD") 212 | (-51, "nD") 213 | (-50, "lD") 214 | (-49, "jD") 215 | (-48, "hD") 216 | (-47, "/C") 217 | (-46, "9C") 218 | (-45, "7C") 219 | (-44, "5C") 220 | (-43, "3C") 221 | (-42, "1C") 222 | (-41, "zC") 223 | (-40, "xC") 224 | (-39, "vC") 225 | (-38, "tC") 226 | (-37, "rC") 227 | (-36, "pC") 228 | (-35, "nC") 229 | (-34, "lC") 230 | (-33, "jC") 231 | (-32, "hC") 232 | (-31, "/B") 233 | (-30, "9B") 234 | (-29, "7B") 235 | (-28, "5B") 236 | (-27, "3B") 237 | (-26, "1B") 238 | (-25, "zB") 239 | (-24, "xB") 240 | (-23, "vB") 241 | (-22, "tB") 242 | (-21, "rB") 243 | (-20, "pB") 244 | (-19, "nB") 245 | (-18, "lB") 246 | (-17, "jB") 247 | (-16, "hB") 248 | (-15, "f") 249 | (-14, "d") 250 | (-13, "b") 251 | (-12, "Z") 252 | (-11, "X") 253 | (-10, "V") 254 | (-9, "T") 255 | (-8, "R") 256 | (-7, "P") 257 | (-6, "N") 258 | (-5, "L") 259 | (-4, "J") 260 | (-3, "H") 261 | (-2, "F") 262 | (-1, "D") 263 | (0, "A") 264 | (1, "C") 265 | (2, "E") 266 | (3, "G") 267 | (4, "I") 268 | (5, "K") 269 | (6, "M") 270 | (7, "O") 271 | (8, "Q") 272 | (9, "S") 273 | (10, "U") 274 | (11, "W") 275 | (12, "Y") 276 | (13, "a") 277 | (14, "c") 278 | (15, "e") 279 | (16, "gB") 280 | (17, "iB") 281 | (18, "kB") 282 | (19, "mB") 283 | (20, "oB") 284 | (21, "qB") 285 | (22, "sB") 286 | (23, "uB") 287 | (24, "wB") 288 | (25, "yB") 289 | (26, "0B") 290 | (27, "2B") 291 | (28, "4B") 292 | (29, "6B") 293 | (30, "8B") 294 | (31, "+B") 295 | (32, "gC") 296 | (33, "iC") 297 | (34, "kC") 298 | (35, "mC") 299 | (36, "oC") 300 | (37, "qC") 301 | (38, "sC") 302 | (39, "uC") 303 | (40, "wC") 304 | (41, "yC") 305 | (42, "0C") 306 | (43, "2C") 307 | (44, "4C") 308 | (45, "6C") 309 | (46, "8C") 310 | (47, "+C") 311 | (48, "gD") 312 | (49, "iD") 313 | (50, "kD") 314 | (51, "mD") 315 | (52, "oD") 316 | (53, "qD") 317 | (54, "sD") 318 | (55, "uD") 319 | (56, "wD") 320 | (57, "yD") 321 | (58, "0D") 322 | (59, "2D") 323 | (60, "4D") 324 | (61, "6D") 325 | (62, "8D") 326 | (63, "+D") 327 | (64, "gE") 328 | (65, "iE") 329 | (66, "kE") 330 | (67, "mE") 331 | (68, "oE") 332 | (69, "qE") 333 | (70, "sE") 334 | (71, "uE") 335 | (72, "wE") 336 | (73, "yE") 337 | (74, "0E") 338 | (75, "2E") 339 | (76, "4E") 340 | (77, "6E") 341 | (78, "8E") 342 | (79, "+E") 343 | (80, "gF") 344 | (81, "iF") 345 | (82, "kF") 346 | (83, "mF") 347 | (84, "oF") 348 | (85, "qF") 349 | (86, "sF") 350 | (87, "uF") 351 | (88, "wF") 352 | (89, "yF") 353 | (90, "0F") 354 | (91, "2F") 355 | (92, "4F") 356 | (93, "6F") 357 | (94, "8F") 358 | (95, "+F") 359 | (96, "gG") 360 | (97, "iG") 361 | (98, "kG") 362 | (99, "mG") 363 | (100, "oG") 364 | (101, "qG") 365 | (102, "sG") 366 | (103, "uG") 367 | (104, "wG") 368 | (105, "yG") 369 | (106, "0G") 370 | (107, "2G") 371 | (108, "4G") 372 | (109, "6G") 373 | (110, "8G") 374 | (111, "+G") 375 | (112, "gH") 376 | (113, "iH") 377 | (114, "kH") 378 | (115, "mH") 379 | (116, "oH") 380 | (117, "qH") 381 | (118, "sH") 382 | (119, "uH") 383 | (120, "wH") 384 | (121, "yH") 385 | (122, "0H") 386 | (123, "2H") 387 | (124, "4H") 388 | (125, "6H") 389 | (126, "8H") 390 | (127, "+H") 391 | (128, "gI") 392 | (129, "iI") 393 | (130, "kI") 394 | (131, "mI") 395 | (132, "oI") 396 | (133, "qI") 397 | (134, "sI") 398 | (135, "uI") 399 | (136, "wI") 400 | (137, "yI") 401 | (138, "0I") 402 | (139, "2I") 403 | (140, "4I") 404 | (141, "6I") 405 | (142, "8I") 406 | (143, "+I") 407 | (144, "gJ") 408 | (145, "iJ") 409 | (146, "kJ") 410 | (147, "mJ") 411 | (148, "oJ") 412 | (149, "qJ") 413 | (150, "sJ") 414 | (151, "uJ") 415 | (152, "wJ") 416 | (157, "6J") 417 | (158, "8J") 418 | (159, "+J") 419 | (160, "gK") 420 | (161, "iK") 421 | (162, "kK") 422 | (163, "mK") 423 | (164, "oK") 424 | (165, "qK") 425 | (166, "sK") 426 | (167, "uK") 427 | (168, "wK") 428 | (169, "yK") 429 | (170, "0K") 430 | (171, "2K") 431 | (172, "4K") 432 | (173, "6K") 433 | (174, "8K") 434 | (175, "+K") 435 | (176, "gL") 436 | (177, "iL") 437 | (178, "kL") 438 | (179, "mL") 439 | (180, "oL") 440 | (181, "qL") 441 | (182, "sL") 442 | (183, "uL") 443 | (184, "wL") 444 | (185, "yL") 445 | (186, "0L") 446 | (187, "2L") 447 | (188, "4L") 448 | (189, "6L") 449 | (190, "8L") 450 | (191, "+L") 451 | (192, "gM") 452 | (193, "iM") 453 | (194, "kM") 454 | (195, "mM") 455 | (196, "oM") 456 | (197, "qM") 457 | (198, "sM") 458 | (199, "uM") 459 | (200, "wM") 460 | (201, "yM") 461 | (202, "0M") 462 | (203, "2M") 463 | (204, "4M") 464 | (205, "6M") 465 | (206, "8M") 466 | (207, "+M") 467 | (208, "gN") 468 | (209, "iN") 469 | (210, "kN") 470 | (211, "mN") 471 | (212, "oN") 472 | (213, "qN") 473 | (214, "sN") 474 | (215, "uN") 475 | (216, "wN") 476 | (217, "yN") 477 | (218, "0N") 478 | (219, "2N") 479 | (220, "4N") 480 | (221, "6N") 481 | (222, "8N") 482 | (223, "+N") 483 | (224, "gO") 484 | (225, "iO") 485 | (226, "kO") 486 | (227, "mO") 487 | (228, "oO") 488 | (229, "qO") 489 | (230, "sO") 490 | (231, "uO") 491 | (232, "wO") 492 | (233, "yO") 493 | (234, "0O") 494 | (235, "2O") 495 | (236, "4O") 496 | (237, "6O") 497 | (238, "8O") 498 | (239, "+O") 499 | (240, "gP") 500 | (241, "iP") 501 | (242, "kP") 502 | (243, "mP") 503 | (244, "oP") 504 | (245, "qP") 505 | (246, "sP") 506 | (247, "uP") 507 | (248, "wP") 508 | (249, "yP") 509 | (250, "0P") 510 | (251, "2P") 511 | (252, "4P") 512 | (253, "6P") 513 | (254, "8P") 514 | (255, "+P") |] 515 | 516 | [] 517 | let ``Base64 encode test out of range encoding`` () = 518 | let action = 519 | Action(fun _ -> Base64.base64Encode -1 |> ignore) 520 | 521 | Assert.Throws(VlqException().GetType(), action) 522 | 523 | [] 524 | let ``Base64 encode test out of range encoding#2`` () = 525 | let action = 526 | Action(fun _ -> Base64.base64Encode 64 |> ignore) 527 | 528 | Assert.Throws(VlqException().GetType(), action) 529 | 530 | [] 531 | let ``test normal encoding and decoding`` () = 532 | for i in [ 0 .. 63 ] do 533 | Base64.base64Encode i |> ignore 534 | 535 | 536 | [] 537 | let ``test normal encoding and decoding for VLQ`` () = 538 | for (num, str) in vlqs do 539 | let s = Base64Vlq.Encode num 540 | Assert.Equal(str, s) -------------------------------------------------------------------------------- /Tests/Program.fs: -------------------------------------------------------------------------------- 1 | module Program = let [] main _ = 0 2 | -------------------------------------------------------------------------------- /Tests/SourceMapGenerator.fs: -------------------------------------------------------------------------------- 1 | module Tests.SourceMapGenerator 2 | 3 | open System 4 | open SourceMapSharp 5 | open Xunit 6 | open SourceMapSharp.Util 7 | open Tests.Util 8 | 9 | module SourceMapGeneratorTests = 10 | let testMap: SourceGeneratorJSON = { 11 | version=3 12 | file="min.js"|>Some 13 | sources= seq {"one.js";"two.js"} 14 | names=seq {"bar";"baz";"n"} 15 | mappings="CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA" 16 | sourcesContent=None 17 | sourceRoot="/the/root"|>Some 18 | } 19 | 20 | [] 21 | let ``test some simple stuff`` () = 22 | let map = SourceMapGenerator(file="foo.js",sourceRoot=".").toJSON() 23 | Assert.True map.file.IsSome 24 | Assert.True map.sourceRoot.IsSome 25 | let map = SourceMapGenerator().toJSON() 26 | Assert.True map.file.IsNone 27 | Assert.True map.sourceRoot.IsNone 28 | 29 | [] 30 | let ``test JSON serialization 1`` () = 31 | let map = SourceMapGenerator(file="foo.js",sourceRoot=".") 32 | let s = map.ToString() 33 | Assert.NotNull s 34 | 35 | [] 36 | let ``test JSON serialization 2`` () = 37 | let s = testMap.Serialize() 38 | Assert.Equal("""{"version":3,"sources":["one.js","two.js"],"names":["bar","baz","n"],"mappings":"CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA","file":"min.js","sourcesContent":null,"sourceRoot":"/the/root"}""", s) 39 | 40 | [] 41 | let ``test adding mappings (case 1)`` () = 42 | let map = SourceMapGenerator(file="generated-foo.js",sourceRoot=".") 43 | let generated: MappingIndex = {line=1;column=1} 44 | map.AddMapping(generated) 45 | 46 | [] 47 | let ``test adding mappings (case 2)`` () = 48 | let map = SourceMapGenerator(file="generated-foo.js",sourceRoot=".") 49 | let generated: MappingIndex = {line=1;column=1} 50 | let original: MappingIndex = {line=1;column=1} 51 | map.AddMapping(generated,original,"bar.js") 52 | 53 | [] 54 | let ``test adding mappings (case 3)`` () = 55 | let map = SourceMapGenerator(file="generated-foo.js",sourceRoot=".") 56 | let generated: MappingIndex = {line=1;column=1} 57 | let original: MappingIndex = {line=1;column=1} 58 | map.AddMapping(generated,original,"bar.js","someToken") 59 | 60 | [] 61 | let ``test adding mappings (invalid)`` () = 62 | let map = SourceMapGenerator(file="generated-foo.js",sourceRoot=".") 63 | let generated: MappingIndex = {line=1;column=1} 64 | let original: MappingIndex = {line=1;column=1} 65 | Assert.Throws(Exception().GetType(),Action(fun _ -> map.AddMapping(generated,original))) 66 | 67 | [] 68 | let ``test adding mappings with skipValidation`` () = 69 | let map = SourceMapGenerator(skipValidation=true, file="generated-foo.js",sourceRoot=".") 70 | let generated: MappingIndex = {line=1;column=1} 71 | let original: MappingIndex = {line=1;column=1} 72 | map.AddMapping(generated,original) 73 | 74 | [] 75 | let ``test that the correct mappings are being generated`` () = 76 | let map = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 77 | let generated: MappingIndex = { line= 1; column= 1 } 78 | let original: MappingIndex = { line= 1; column= 1 } 79 | map.AddMapping(generated, original, "one.js") 80 | 81 | let generated: MappingIndex = { line= 1; column= 5 } 82 | let original: MappingIndex = { line= 1; column= 5 } 83 | map.AddMapping(generated, original, "one.js") 84 | 85 | let generated: MappingIndex = { line= 1; column= 9 } 86 | let original: MappingIndex = { line= 1; column= 11 } 87 | map.AddMapping(generated, original, "one.js") 88 | 89 | let generated: MappingIndex = { line= 1; column= 18 } 90 | let original: MappingIndex = { line= 1; column= 21 } 91 | map.AddMapping(generated, original, "one.js", "bar") 92 | 93 | let generated: MappingIndex = { line= 1; column= 21 } 94 | let original: MappingIndex = { line= 2; column= 3 } 95 | map.AddMapping(generated, original, "one.js") 96 | 97 | let generated: MappingIndex = { line= 1; column= 28 } 98 | let original: MappingIndex = { line= 2; column= 10 } 99 | map.AddMapping(generated, original, "one.js", "baz") 100 | 101 | let generated: MappingIndex = { line= 1; column= 32 } 102 | let original: MappingIndex = { line= 2; column= 14 } 103 | map.AddMapping(generated, original, "one.js", "bar") 104 | 105 | let generated: MappingIndex = { line= 2; column= 1 } 106 | let original: MappingIndex = { line= 1; column= 1 } 107 | map.AddMapping(generated, original, "two.js") 108 | 109 | let generated: MappingIndex = { line= 2; column= 5 } 110 | let original: MappingIndex = { line= 1; column= 5 } 111 | map.AddMapping(generated, original, "two.js") 112 | 113 | let generated: MappingIndex = { line= 2; column= 9 } 114 | let original: MappingIndex = { line= 1; column= 11 } 115 | map.AddMapping(generated, original, "two.js") 116 | 117 | let generated: MappingIndex = { line= 2; column= 18 } 118 | let original: MappingIndex = { line= 1; column= 21 } 119 | map.AddMapping(generated, original, "two.js", "n") 120 | 121 | let generated: MappingIndex = { line= 2; column= 21 } 122 | let original: MappingIndex = { line= 2; column= 3 } 123 | map.AddMapping(generated, original, "two.js") 124 | 125 | let generated: MappingIndex = { line= 2; column= 28 } 126 | let original: MappingIndex = { line= 2; column= 10 } 127 | map.AddMapping(generated, original, "two.js", "n") 128 | 129 | TestUtils.assertEqualSourceMaps(map,testMap) 130 | 131 | 132 | [] 133 | let ``test that adding a mapping with an empty string name does not break generation`` () = 134 | let map = SourceMapGenerator(file="generated-foo.js",sourceRoot=".") 135 | let generated: MappingIndex = {line=1;column=1} 136 | let original: MappingIndex = {line=1;column=1} 137 | map.AddMapping(generated,original, source="bar.js",name="") 138 | map.ToString() 139 | 140 | [] 141 | let ``test that source content can be set`` () = 142 | let map = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 143 | let generated: MappingIndex = { line= 1; column= 1 } 144 | let original: MappingIndex = { line= 1; column= 1 } 145 | map.AddMapping(generated, original, "one.js") 146 | let generated: MappingIndex = { line= 2; column= 1 } 147 | let original: MappingIndex = { line= 1; column= 1 } 148 | map.AddMapping(generated, original, "two.js") 149 | map.SetSourceContent("one.js",Some "one file content") 150 | let j = map.toJSON() 151 | let _src = j.sources |> Array.ofSeq 152 | let _srcC = j.sourcesContent.Value |> Array.ofSeq 153 | Assert.True (_src.[0] = "one.js") 154 | Assert.True (_src.[1] = "two.js") 155 | Assert.True(_srcC.[0].Value = "one file content") 156 | Assert.True(_srcC.[1].IsNone) 157 | [] 158 | let ``test sorting with duplicate generated mappings`` () = 159 | let map = SourceMapGenerator(file="test.js") 160 | let generated1: MappingIndex = { line= 3; column= 0 } 161 | let original1: MappingIndex = { line= 2; column= 0 } 162 | map.AddMapping(generated1, original1, "a.js") 163 | 164 | let generated2: MappingIndex = { line= 2; column= 0 } 165 | map.AddMapping(generated2) 166 | 167 | let generated3: MappingIndex = { line= 2; column= 0 } 168 | map.AddMapping(generated3) 169 | 170 | let generated4: MappingIndex = { line= 1; column= 0 } 171 | let original4: MappingIndex = { line= 1; column= 0 } 172 | map.AddMapping(generated4, original4, "a.js") 173 | let expected = { 174 | version=3 175 | file="test.js"|>Some 176 | sources= seq {"a.js"} 177 | names= Seq.empty 178 | mappings="AAAA;A;AACA" 179 | sourcesContent=None 180 | sourceRoot=None 181 | } 182 | TestUtils.assertEqualSourceMaps(map,expected) 183 | [] 184 | let ``test ignore duplicate mappings.`` () = 185 | let map1 = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 186 | let map2 = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 187 | 188 | let nullMapping1: MappingIndex = { line= 1; column= 0 } 189 | let nullMapping2: MappingIndex = { line= 2; column= 2 } 190 | 191 | map1.AddMapping(nullMapping1) 192 | map1.AddMapping(nullMapping1) 193 | 194 | map2.AddMapping(nullMapping1) 195 | 196 | TestUtils.assertEqualSourceMaps(map1,map2) 197 | 198 | map1.AddMapping(nullMapping2) 199 | map1.AddMapping(nullMapping1) 200 | 201 | map2.AddMapping(nullMapping2) 202 | 203 | TestUtils.assertEqualSourceMaps(map1,map2) 204 | 205 | let srcMapping1Generated: MappingIndex = { line= 1; column= 0 } 206 | let srcMapping1Original: MappingIndex = { line= 11; column= 0 } 207 | let srcMapping1Source = "srcMapping1.js" 208 | 209 | let srcMapping2Generated: MappingIndex = { line= 2; column= 2 } 210 | let srcMapping2Original: MappingIndex = { line= 11; column= 0 } 211 | let srcMapping2Source = "srcMapping2.js" 212 | 213 | let map1 = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 214 | let map2 = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 215 | 216 | map1.AddMapping(srcMapping1Generated,srcMapping1Original,srcMapping1Source) 217 | map1.AddMapping(srcMapping1Generated,srcMapping1Original,srcMapping1Source) 218 | 219 | map2.AddMapping(srcMapping1Generated,srcMapping1Original,srcMapping1Source) 220 | 221 | TestUtils.assertEqualSourceMaps(map1,map2) 222 | 223 | map1.AddMapping(srcMapping2Generated,srcMapping2Original,srcMapping2Source) 224 | map1.AddMapping(srcMapping1Generated,srcMapping1Original,srcMapping1Source) 225 | 226 | map2.AddMapping(srcMapping2Generated,srcMapping2Original,srcMapping2Source) 227 | 228 | TestUtils.assertEqualSourceMaps(map1,map2) 229 | 230 | 231 | let fullMapping1Generated: MappingIndex = { line= 1; column= 0 } 232 | let fullMapping1Original: MappingIndex = { line= 11; column= 0 } 233 | let fullMapping1Source = "fullMapping1.js" 234 | let fullMapping1Name = "fullMapping1" 235 | 236 | let fullMapping2Generated: MappingIndex = { line= 2; column= 2 } 237 | let fullMapping2Original: MappingIndex = { line= 11; column= 0 } 238 | let fullMapping2Source = "fullMapping2.js" 239 | let fullMapping2Name = "fullMapping2" 240 | 241 | let map1 = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 242 | let map2 = SourceMapGenerator(file="min.js",sourceRoot="/the/root") 243 | 244 | map1.AddMapping(fullMapping1Generated,fullMapping1Original,fullMapping1Source,fullMapping1Name) 245 | map1.AddMapping(fullMapping1Generated,fullMapping1Original,fullMapping1Source,fullMapping1Name) 246 | 247 | map2.AddMapping(fullMapping1Generated,fullMapping1Original,fullMapping1Source,fullMapping1Name) 248 | 249 | TestUtils.assertEqualSourceMaps(map1,map2) 250 | 251 | map1.AddMapping(fullMapping2Generated,fullMapping2Original,fullMapping2Source,fullMapping2Name) 252 | map1.AddMapping(fullMapping1Generated,fullMapping1Original,fullMapping1Source,fullMapping1Name) 253 | 254 | map2.AddMapping(fullMapping2Generated,fullMapping2Original,fullMapping2Source,fullMapping2Name) 255 | TestUtils.assertEqualSourceMaps(map1,map2) 256 | 257 | 258 | [] 259 | let ``test github issue #72, check for duplicate names or sources`` () = 260 | let map = SourceMapGenerator(file="test.js") 261 | let generated1: MappingIndex = { line= 1; column= 1 } 262 | let original1: MappingIndex = { line= 2; column= 2 } 263 | map.AddMapping(generated1, original1, "a.js", "foo") 264 | 265 | let generated2: MappingIndex = { line= 3; column= 3 } 266 | let original2: MappingIndex = { line= 4; column= 4 } 267 | map.AddMapping(generated2, original2, "a.js", "foo") 268 | 269 | let expected = { 270 | version=3 271 | file="test.js"|>Some 272 | sources= seq {"a.js"} 273 | names= seq {"foo"} 274 | mappings="CACEA;;GAEEA" 275 | sourcesContent=None 276 | sourceRoot=None 277 | } 278 | TestUtils.assertEqualSourceMaps(map,expected) 279 | 280 | [] 281 | let ``test setting sourcesContent to null when already null`` () = 282 | let map = SourceMapGenerator(file="foo.js") 283 | map.SetSourceContent("bar.js",None) 284 | 285 | [] 286 | let ``test numeric names #231`` () = 287 | let map = SourceMapGenerator() 288 | let generated: MappingIndex = {line=1;column=10} 289 | let original: MappingIndex = {line=1;column=10} 290 | // type safe names! can't pass number 291 | map.AddMapping(generated,original, source="a.js",name="8") 292 | 293 | let m = map.toJSON() 294 | Assert.Equal(m.names |> Seq.length,1) 295 | Assert.Equal(m.names |> Seq.head,"8") -------------------------------------------------------------------------------- /Tests/SourceNode.fs: -------------------------------------------------------------------------------- 1 | module Tests.SourceNode 2 | 3 | open SourceMapSharp 4 | open Xunit 5 | open SourceMapSharp.Util 6 | open Tests.Util 7 | module SourceNodeTests = 8 | [] 9 | let ``test .add()`` () = 10 | let node = SourceNode() 11 | node.Add(SourceChunk.ChunkS "function noop() {}") |> ignore 12 | node.Add(SourceChunk.ChunkArrSN [|SourceNode()|]) |> ignore 13 | node.Add(SourceChunk.ChunkArrSN [|SourceNode(_chunks=[|SourceChunk.ChunkS "return 10;"|])|]) |> ignore 14 | node.Add(SourceChunk.ChunkArrS [|"function foo() {";"}"|]) |> ignore 15 | [] 16 | let ``test .prepend()`` () = 17 | let node = SourceNode() 18 | let s = "function noop() {}" 19 | node.Prepend(SourceChunk.ChunkS s) |> ignore 20 | Assert.Equal(node.children.[0],SourceNodeChild.S s) 21 | Assert.Equal(node.children.Count,1) 22 | 23 | node.Prepend(SourceChunk.ChunkArrSN [|SourceNode()|]) |> ignore 24 | Assert.True(match node.children.[0] with | SN _ -> true | S _ -> false) 25 | Assert.True(match node.children.[1] with | SN _ -> false | S _ -> true) 26 | Assert.True(match node.children.[1] with | SN _ -> false | S ss -> s = ss) 27 | Assert.True(node.children.Count = 2) 28 | 29 | node.Prepend( 30 | [|SourceChunk.ChunkS "function foo() {" 31 | SourceChunk.ChunkArrSN [|SourceNode(_chunks=[|SourceChunk.ChunkS "return 10;"|])|] 32 | SourceChunk.ChunkS "}" 33 | |]) |> ignore 34 | 35 | Assert.Equal(node.children.[0].ToString(), "function foo() {") 36 | Assert.Equal(node.children.[1].ToString(), "return 10;") 37 | Assert.Equal(node.children.[2].ToString(), "}") 38 | Assert.Equal(node.children.[3].ToString(), "") 39 | Assert.Equal(node.children.[4].ToString(), "function noop() {}") 40 | Assert.True(node.children.Count = 5) 41 | 42 | [] 43 | let ``test .toString()`` () = 44 | let node = SourceNode(_chunks=[| 45 | SourceChunk.ChunkS "function foo() {" 46 | SourceChunk.ChunkArrSN [|SourceNode(_chunks=[|SourceChunk.ChunkS "return 10;"|])|] 47 | SourceChunk.ChunkS "}" 48 | |]) 49 | Assert.Equal(node.ToString(),"function foo() {return 10;}") 50 | 51 | [] 52 | let ``test .join()`` () = 53 | let node = SourceNode(_chunks=[| 54 | SourceChunk.ChunkS "a" 55 | SourceChunk.ChunkS "b" 56 | SourceChunk.ChunkS "c" 57 | SourceChunk.ChunkS "d" 58 | |]) 59 | Assert.Equal("a, b, c, d", node.Join(", ").ToString()) 60 | 61 | [] 62 | let ``test .walk()`` () = 63 | let node = SourceNode(_chunks=[| 64 | SourceChunk.ChunkS "(function () {\n" 65 | SourceChunk.ChunkS " " 66 | SourceChunk.ChunkArrSN [| 67 | SourceNode(_line=1,_column=0,_source="a.js", 68 | _chunks=[|SourceChunk.ChunkS "someCall()"|]) 69 | |] 70 | SourceChunk.ChunkS ";\n" 71 | SourceChunk.ChunkS " " 72 | SourceChunk.ChunkArrSN [| 73 | SourceNode(_line=2,_column=0,_source="b.js", 74 | _chunks=[|SourceChunk.ChunkS "if (foo) bar()"|]) 75 | |] 76 | SourceChunk.ChunkS ";\n" 77 | SourceChunk.ChunkS "}());" 78 | |]) 79 | 80 | let expected = [| 81 | {| str= "(function () {\n"; source= None; line= None; column= None |} 82 | {| str= " "; source= None; line= None; column= None |} 83 | {| str= "someCall()"; source= Some "a.js"; line= Some 1; column= Some 0 |} 84 | {| str= ";\n"; source= None; line= None; column= None |} 85 | {| str= " "; source= None; line= None; column= None |} 86 | {| str= "if (foo) bar()"; source= Some "b.js"; line= Some 2; column= Some 0 |} 87 | {| str= ";\n"; source= None; line= None; column= None |} 88 | {| str= "}());"; source= None; line= None; column= None |} 89 | |] 90 | 91 | 92 | let mutable i = 0 93 | node.Walk(fun chunk loc -> 94 | Assert.Equal(expected.[i].str,chunk) 95 | Assert.Equal(expected.[i].source, loc.Source) 96 | Assert.Equal(expected.[i].line, loc.line) 97 | Assert.Equal(expected.[i].column, loc.column) 98 | i <- i+1 99 | ) 100 | 101 | [] 102 | let ``test .replaceRight()`` () = 103 | // Not nested 104 | let node = SourceNode(_chunks=[| 105 | SourceChunk.ChunkS "hello world" 106 | |]) 107 | node.ReplaceRight("world","universe") |> ignore 108 | Assert.Equal("hello universe", node.ToString()) 109 | 110 | // Nested 111 | let node = SourceNode(_chunks=[| 112 | SourceChunk.ChunkArrSN [| 113 | SourceNode(_chunks=[| 114 | SourceChunk.ChunkS "hey sexy mama, " 115 | |]) 116 | SourceNode(_chunks=[| 117 | SourceChunk.ChunkS "want to kill all humans?" 118 | |]) 119 | |] 120 | |]) 121 | node.ReplaceRight("kill all humans", "watch Futurama") |> ignore 122 | Assert.Equal("hey sexy mama, want to watch Futurama?", node.ToString()) 123 | 124 | 125 | [] 126 | let ``test .toStringWithSourceMap()`` () = 127 | ["\n";"\r\n"] |> List.iter (fun nl -> 128 | let c1 = SourceChunk.ChunkS ("(function () {" + nl) 129 | let c2 = SourceChunk.ChunkS (" ") 130 | let c3 = SourceNode(_line=1,_column=0,_source="a.js", _name="originalCall", 131 | _chunks=[|SourceChunk.ChunkS "someCall"|]) 132 | let c4 = SourceNode(_line=1,_column=8,_source="a.js", 133 | _chunks=[|SourceChunk.ChunkS "()"|]) 134 | let c5 = SourceChunk.ChunkS (";" + nl) 135 | let c6 = SourceChunk.ChunkS (" ") 136 | let c7 = SourceNode(_line=2,_column=0,_source="b.js", 137 | _chunks=[|SourceChunk.ChunkS "if (foo) bar()"|]) 138 | let c8 = SourceChunk.ChunkS (";" + nl) 139 | let c9 = SourceChunk.ChunkS ("}());") 140 | let node = SourceNode(_chunks=[| 141 | c1 142 | c2 143 | SourceChunk.ChunkArrSN ([|c3;c4|]) 144 | c5 145 | c6 146 | SourceChunk.ChunkArrSN ([|c7|]) 147 | c8 148 | c9 149 | |]) 150 | let (code, resultMap) = node.ToStringWithSourceMap(file="foo.js") 151 | let expected = String.concat nl [ 152 | "(function () {" 153 | " someCall();" 154 | " if (foo) bar();" 155 | "}());" 156 | ] 157 | Assert.Equal(expected, code) 158 | //todo: sourcemapconsumer part 159 | ) 160 | [] 161 | let ``test .toStringWithSourceMap() with consecutive newlines`` () = 162 | ["\n";"\r\n"] |> List.iter (fun nl -> 163 | let c1 = SourceChunk.ChunkS ("/***/" + nl + nl) 164 | let c2 = SourceNode(_line=1,_column=0,_source="a.js", 165 | _chunks=[|SourceChunk.ChunkS ("'use strict';" + nl)|]) 166 | let c3 = SourceNode(_line=2,_column=0,_source="a.js", 167 | _chunks=[|SourceChunk.ChunkS "a();"|]) 168 | let input = SourceNode(_chunks=[| 169 | c1 170 | SourceChunk.ChunkArrSN ([|c2;c3|]) 171 | |]) 172 | let (code, inputMap) = input.ToStringWithSourceMap(file="foo.js") 173 | let expected = String.concat nl [ 174 | "/***/" 175 | "" 176 | "'use strict';" 177 | "a();" 178 | ] 179 | Assert.Equal(expected, code) 180 | 181 | let map = SourceMapGenerator(file="foo.js") 182 | let generated: MappingIndex = { line= 3; column= 0 } 183 | let original: MappingIndex = { line= 1; column= 0 } 184 | map.AddMapping(generated, original, "a.js") 185 | let generated: MappingIndex = { line= 4; column= 0 } 186 | let original: MappingIndex = { line= 2; column= 0 } 187 | map.AddMapping(generated, original, "a.js") 188 | TestUtils.assertEqualSourceMaps(map,inputMap) 189 | ) 190 | 191 | [] 192 | let ``test .toStringWithSourceMap() merging duplicate mappings`` () = 193 | ["\n";"\r\n"] |> List.iter (fun nl -> 194 | let c1 = SourceNode(_line=1,_column=0,_source="a.js", _chunks=[|SourceChunk.ChunkS ("(function")|]) 195 | let c2 = SourceNode(_line=1,_column=0,_source="a.js",_chunks=[|SourceChunk.ChunkS ("() {" + nl)|]) 196 | let c3 = SourceChunk.ChunkS (" ") 197 | let c4 = SourceNode(_line=1,_column=0,_source="a.js",_chunks=[|SourceChunk.ChunkS ("var Test = ")|]) 198 | let c5 = SourceNode(_line=1,_column=0,_source="b.js",_chunks=[|SourceChunk.ChunkS ("{};" + nl)|]) 199 | let c6 = SourceNode(_line=2,_column=0,_source="b.js",_chunks=[|SourceChunk.ChunkS ("Test")|]) 200 | let c7 = SourceNode(_line=2,_column=0,_source="b.js",_name="A",_chunks=[|SourceChunk.ChunkS (".A")|]) 201 | let c8 = SourceNode(_line=2,_column=20,_source="b.js",_name="A",_chunks=[|SourceChunk.ChunkS (" = { value: ")|]) 202 | let c9 = SourceChunk.ChunkS ("1234") 203 | let c10 = SourceNode(_line=2,_column=40,_source="b.js",_name="A",_chunks=[|SourceChunk.ChunkS (" };" + nl)|]) 204 | let c11 = SourceChunk.ChunkS ("}());" + nl) 205 | let c12 = SourceChunk.ChunkS ("/* Generated Source */") 206 | let input = SourceNode(_chunks=[| 207 | SourceChunk.ChunkArrSN ([|c1;c2|]) 208 | c3 209 | SourceChunk.ChunkArrSN ([|c4;c5;c6;c7;c8|]) 210 | c9 211 | SourceChunk.ChunkArrSN ([|c10|]) 212 | c11 213 | c12 214 | |]) 215 | let (code, inputMap) = input.ToStringWithSourceMap(file="foo.js") 216 | let expected = String.concat nl [ 217 | "(function() {" 218 | " var Test = {};" 219 | "Test.A = { value: 1234 };" 220 | "}());" 221 | "/* Generated Source */" ] 222 | Assert.Equal(expected, code) 223 | 224 | let map = SourceMapGenerator(file="foo.js") 225 | let generated: MappingIndex = { line= 1; column= 0 } 226 | let original: MappingIndex = { line= 1; column= 0 } 227 | map.AddMapping(generated, original, "a.js") 228 | 229 | // Here is no need for a empty mapping, 230 | // because mappings ends at eol 231 | let generated: MappingIndex = { line= 2; column= 2 } 232 | let original: MappingIndex = { line= 1; column= 0 } 233 | map.AddMapping(generated, original, "a.js") 234 | 235 | let generated: MappingIndex = { line= 2; column= 13 } 236 | let original: MappingIndex = { line= 1; column= 0 } 237 | map.AddMapping(generated, original, "b.js") 238 | 239 | 240 | let generated: MappingIndex = { line= 3; column= 0 } 241 | let original: MappingIndex = { line= 2; column= 0 } 242 | map.AddMapping(generated, original, "b.js") 243 | 244 | let generated: MappingIndex = { line= 3; column= 4 } 245 | let original: MappingIndex = { line= 2; column= 0 } 246 | map.AddMapping(generated, original, "b.js", name="A") 247 | 248 | let generated: MappingIndex = { line= 3; column= 6 } 249 | let original: MappingIndex = { line= 2; column= 20 } 250 | map.AddMapping(generated, original, "b.js", name="A") 251 | 252 | // This empty mapping is required, 253 | // because there is a hole in the middle of the line 254 | let generated: MappingIndex = { line= 3; column= 18 } 255 | map.AddMapping(generated) 256 | 257 | let generated: MappingIndex = { line= 3; column= 22 } 258 | let original: MappingIndex = { line= 2; column= 40 } 259 | map.AddMapping(generated, original, "b.js", name="A") 260 | // Here is no need for a empty mapping, 261 | // because mappings ends at eol 262 | TestUtils.assertEqualSourceMaps(map,inputMap) 263 | ) 264 | 265 | 266 | [] 267 | let ``test .toStringWithSourceMap() multi-line SourceNodes`` () = 268 | ["\n";"\r\n"] |> List.iter (fun nl -> 269 | let c1 = SourceNode(_line=1,_column=0,_source="a.js", 270 | _chunks=[|SourceChunk.ChunkS ("(function() {" + nl + "var nextLine = 1;" + nl + "anotherLine();" + nl)|]) 271 | let c2 = SourceNode(_line=2,_column=2,_source="b.js",_chunks=[|SourceChunk.ChunkS ("Test.call(this, 123);" + nl)|]) 272 | let c3 = SourceNode(_line=2,_column=2,_source="b.js",_chunks=[|SourceChunk.ChunkS ("this['stuff'] = 'v';" + nl)|]) 273 | let c4 = SourceNode(_line=2,_column=2,_source="b.js",_chunks=[|SourceChunk.ChunkS ("anotherLine();" + nl)|]) 274 | let c5 = SourceChunk.ChunkS ("/*" + nl + "Generated" + nl + "Source" + nl + "*/" + nl) 275 | let c6 = SourceNode(_line=3,_column=4,_source="c.js",_chunks=[|SourceChunk.ChunkS ("anotherLine();" + nl)|]) 276 | let c7 = SourceChunk.ChunkS ("/*" + nl + "Generated" + nl + "Source" + nl + "*/") 277 | 278 | let input = SourceNode(_chunks=[| 279 | SourceChunk.ChunkArrSN ([|c1;c2;c3;c4|]) 280 | c5 281 | SourceChunk.ChunkArrSN ([|c6|]) 282 | c7 283 | |]) 284 | let (code, inputMap) = input.ToStringWithSourceMap(file="foo.js") 285 | let expected = String.concat nl [ 286 | "(function() {" 287 | "var nextLine = 1;" 288 | "anotherLine();" 289 | "Test.call(this, 123);" 290 | "this['stuff'] = 'v';" 291 | "anotherLine();" 292 | "/*" 293 | "Generated" 294 | "Source" 295 | "*/" 296 | "anotherLine();" 297 | "/*" 298 | "Generated" 299 | "Source" 300 | "*/" ] 301 | Assert.Equal(expected, code) 302 | 303 | let map = SourceMapGenerator(file="foo.js") 304 | let generated: MappingIndex = { line= 1; column= 0 } 305 | let original: MappingIndex = { line= 1; column= 0 } 306 | map.AddMapping(generated, original, "a.js") 307 | 308 | let generated: MappingIndex = { line= 2; column= 0 } 309 | let original: MappingIndex = { line= 1; column= 0 } 310 | map.AddMapping(generated, original, "a.js") 311 | 312 | let generated: MappingIndex = { line= 3; column= 0 } 313 | let original: MappingIndex = { line= 1; column= 0 } 314 | map.AddMapping(generated, original, "a.js") 315 | 316 | let generated: MappingIndex = { line= 4; column= 0 } 317 | let original: MappingIndex = { line= 2; column= 2 } 318 | map.AddMapping(generated, original, "b.js") 319 | 320 | let generated: MappingIndex = { line= 5; column= 0 } 321 | let original: MappingIndex = { line= 2; column= 2 } 322 | map.AddMapping(generated, original, "b.js") 323 | 324 | let generated: MappingIndex = { line= 6; column= 0 } 325 | let original: MappingIndex = { line= 2; column= 2 } 326 | map.AddMapping(generated, original, "b.js") 327 | 328 | let generated: MappingIndex = { line= 11; column= 0 } 329 | let original: MappingIndex = { line= 3; column= 4 } 330 | map.AddMapping(generated, original, "c.js") 331 | 332 | TestUtils.assertEqualSourceMaps(map,inputMap) 333 | 334 | ) 335 | 336 | [] 337 | let ``test .toStringWithSourceMap() with empty string`` () = 338 | let node = SourceNode(_line=1,_column=0,_source="empty.js",_chunks=[|SourceChunk.ChunkS ""|]) 339 | let (code, _) = node.ToStringWithSourceMap(file="") 340 | Assert.Equal(code,"") 341 | 342 | [] 343 | let ``test setSourceContent with toStringWithSourceMap`` () = 344 | let aNode = SourceNode(_line=1,_column=1,_source="a.js",_chunks=[|SourceChunk.ChunkS "a"|]) 345 | aNode.SetSourceContent("a.js","someContent") 346 | let node = SourceNode(_chunks=[| 347 | SourceChunk.ChunkS "(function () {\n" 348 | SourceChunk.ChunkS " " 349 | SourceChunk.ChunkArrSN [| aNode |] 350 | SourceChunk.ChunkS " " 351 | SourceChunk.ChunkArrSN [| 352 | SourceNode(_line=1,_column=1,_source="b.js",_chunks=[|SourceChunk.ChunkS "b"|]) 353 | |] 354 | SourceChunk.ChunkS "}());" 355 | |]) 356 | node.SetSourceContent("b.js","otherContent") 357 | let (_, map) = node.ToStringWithSourceMap(file="foo.js") 358 | Assert.NotNull(map) //dummy assert 359 | 360 | Assert.Equal(map._sources.Size(), 2) 361 | Assert.Equal(map._sources.At(0).Value, "a.js") 362 | Assert.Equal(map._sources.At(1).Value, "b.js") 363 | Assert.Equal(map._sourcesContents.Count, 2) 364 | let sc = map._sourcesContents |> Seq.map (fun kvp -> kvp.Value) |> Array.ofSeq 365 | Assert.Equal(sc.[0], "someContent") 366 | Assert.Equal(sc.[1], "otherContent") 367 | 368 | [] 369 | let ``test walkSourceContents`` () = 370 | let aNode = SourceNode(_line=1,_column=0,_source="a.js",_chunks=[|SourceChunk.ChunkS "a"|]) 371 | aNode.SetSourceContent("a.js","someContent") 372 | let node = SourceNode(_chunks=[| 373 | SourceChunk.ChunkS "(function () {\n" 374 | SourceChunk.ChunkS " " 375 | SourceChunk.ChunkArrSN [| aNode |] 376 | SourceChunk.ChunkS " " 377 | SourceChunk.ChunkArrSN [| 378 | SourceNode(_line=1,_column=1,_source="b.js",_chunks=[|SourceChunk.ChunkS "b"|]) 379 | |] 380 | SourceChunk.ChunkS "}());" 381 | |]) 382 | node.SetSourceContent("b.js","otherContent") 383 | let results = ResizeArray<_>() 384 | node.WalkSourceContents(results.Add) 385 | Assert.Equal(results.Count, 2) 386 | Assert.Equal(fst results.[0], "a.js") 387 | Assert.Equal(snd results.[0], "someContent") 388 | Assert.Equal(fst results.[1], "b.js") 389 | Assert.Equal(snd results.[1], "otherContent") 390 | -------------------------------------------------------------------------------- /Tests/Tests.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | Major 6 | false 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Tests/Util.fs: -------------------------------------------------------------------------------- 1 | module Tests.Util 2 | 3 | open SourceMapSharp 4 | open SourceMapSharp.Util 5 | open Xunit 6 | open System.Text.Json 7 | 8 | type TestUtils = 9 | static member assertEqualSourceMaps(s1:SourceMapGenerator,s2:SourceMapGenerator) = 10 | Assert.Equal (s1.ToString(),s2.ToString()) 11 | 12 | static member assertEqualSourceMaps(s1:SourceMapGenerator,s2:SourceGeneratorJSON) = 13 | Assert.Equal (s1.ToString(),s2.Serialize()) 14 | 15 | module UtilTests = 16 | [] 17 | let ``test relative()`` () = 18 | 19 | Assert.Equal(Util.getRelativePath("/the/root","/the/root/one.js"), "one.js") 20 | 21 | Assert.Equal( 22 | Util.getRelativePath("http://the/root", "http://the/root/one.js"), 23 | "one.js" 24 | ) 25 | 26 | Assert.Equal( 27 | Util.getRelativePath("/the/root", "/the/rootone.js"), 28 | "../rootone.js" 29 | ) 30 | 31 | Assert.Equal( 32 | Util.getRelativePath("http://the/root", "http://the/rootone.js"), 33 | "../rootone.js" 34 | ) 35 | 36 | Assert.Equal( 37 | Util.getRelativePath("/the/root", "/therootone.js"), 38 | "../../therootone.js" 39 | ) 40 | 41 | Assert.Equal( 42 | Util.getRelativePath("http://the/root", "/therootone.js"), 43 | "/therootone.js" 44 | ) 45 | 46 | Assert.Equal(Util.getRelativePath("", "/the/root/one.js"), "/the/root/one.js") 47 | 48 | Assert.Equal(Util.getRelativePath(".", "/the/root/one.js"), "/the/root/one.js") 49 | 50 | Assert.Equal(Util.getRelativePath("", "the/root/one.js"), "the/root/one.js") 51 | 52 | Assert.Equal(Util.getRelativePath(".", "the/root/one.js"), "the/root/one.js") 53 | 54 | Assert.Equal(Util.getRelativePath("/", "/the/root/one.js"), "the/root/one.js") 55 | 56 | Assert.Equal(Util.getRelativePath("/", "the/root/one.js"), "the/root/one.js") -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "type": "module", 4 | "scripts": { 5 | "fable": "dotnet fable source-map-sharp.fsproj --outDir build", 6 | "pretest": "dotnet fable Tests.Fable/Tests.Fable.fsproj --outDir build/tests/", 7 | "test": "mocha build/tests/Tests.js" 8 | }, 9 | "devDependencies": { 10 | "mocha": "^9.2.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.3 2 | 3 | specifiers: 4 | mocha: ^9.2.0 5 | 6 | devDependencies: 7 | mocha: 9.2.0 8 | 9 | packages: 10 | 11 | /@ungap/promise-all-settled/1.1.2: 12 | resolution: {integrity: sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==} 13 | dev: true 14 | 15 | /ansi-colors/4.1.1: 16 | resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} 17 | engines: {node: '>=6'} 18 | dev: true 19 | 20 | /ansi-regex/5.0.1: 21 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 22 | engines: {node: '>=8'} 23 | dev: true 24 | 25 | /ansi-styles/4.3.0: 26 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 27 | engines: {node: '>=8'} 28 | dependencies: 29 | color-convert: 2.0.1 30 | dev: true 31 | 32 | /anymatch/3.1.2: 33 | resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} 34 | engines: {node: '>= 8'} 35 | dependencies: 36 | normalize-path: 3.0.0 37 | picomatch: 2.3.1 38 | dev: true 39 | 40 | /argparse/2.0.1: 41 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 42 | dev: true 43 | 44 | /balanced-match/1.0.2: 45 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 46 | dev: true 47 | 48 | /binary-extensions/2.2.0: 49 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} 50 | engines: {node: '>=8'} 51 | dev: true 52 | 53 | /brace-expansion/1.1.11: 54 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 55 | dependencies: 56 | balanced-match: 1.0.2 57 | concat-map: 0.0.1 58 | dev: true 59 | 60 | /braces/3.0.2: 61 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} 62 | engines: {node: '>=8'} 63 | dependencies: 64 | fill-range: 7.0.1 65 | dev: true 66 | 67 | /browser-stdout/1.3.1: 68 | resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} 69 | dev: true 70 | 71 | /camelcase/6.3.0: 72 | resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} 73 | engines: {node: '>=10'} 74 | dev: true 75 | 76 | /chalk/4.1.2: 77 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 78 | engines: {node: '>=10'} 79 | dependencies: 80 | ansi-styles: 4.3.0 81 | supports-color: 7.2.0 82 | dev: true 83 | 84 | /chokidar/3.5.3: 85 | resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} 86 | engines: {node: '>= 8.10.0'} 87 | dependencies: 88 | anymatch: 3.1.2 89 | braces: 3.0.2 90 | glob-parent: 5.1.2 91 | is-binary-path: 2.1.0 92 | is-glob: 4.0.3 93 | normalize-path: 3.0.0 94 | readdirp: 3.6.0 95 | optionalDependencies: 96 | fsevents: 2.3.2 97 | dev: true 98 | 99 | /cliui/7.0.4: 100 | resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} 101 | dependencies: 102 | string-width: 4.2.3 103 | strip-ansi: 6.0.1 104 | wrap-ansi: 7.0.0 105 | dev: true 106 | 107 | /color-convert/2.0.1: 108 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 109 | engines: {node: '>=7.0.0'} 110 | dependencies: 111 | color-name: 1.1.4 112 | dev: true 113 | 114 | /color-name/1.1.4: 115 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 116 | dev: true 117 | 118 | /concat-map/0.0.1: 119 | resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} 120 | dev: true 121 | 122 | /debug/4.3.3_supports-color@8.1.1: 123 | resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} 124 | engines: {node: '>=6.0'} 125 | peerDependencies: 126 | supports-color: '*' 127 | peerDependenciesMeta: 128 | supports-color: 129 | optional: true 130 | dependencies: 131 | ms: 2.1.2 132 | supports-color: 8.1.1 133 | dev: true 134 | 135 | /decamelize/4.0.0: 136 | resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} 137 | engines: {node: '>=10'} 138 | dev: true 139 | 140 | /diff/5.0.0: 141 | resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} 142 | engines: {node: '>=0.3.1'} 143 | dev: true 144 | 145 | /emoji-regex/8.0.0: 146 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 147 | dev: true 148 | 149 | /escalade/3.1.1: 150 | resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} 151 | engines: {node: '>=6'} 152 | dev: true 153 | 154 | /escape-string-regexp/4.0.0: 155 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 156 | engines: {node: '>=10'} 157 | dev: true 158 | 159 | /fill-range/7.0.1: 160 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} 161 | engines: {node: '>=8'} 162 | dependencies: 163 | to-regex-range: 5.0.1 164 | dev: true 165 | 166 | /find-up/5.0.0: 167 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} 168 | engines: {node: '>=10'} 169 | dependencies: 170 | locate-path: 6.0.0 171 | path-exists: 4.0.0 172 | dev: true 173 | 174 | /flat/5.0.2: 175 | resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} 176 | hasBin: true 177 | dev: true 178 | 179 | /fs.realpath/1.0.0: 180 | resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=} 181 | dev: true 182 | 183 | /fsevents/2.3.2: 184 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 185 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 186 | os: [darwin] 187 | requiresBuild: true 188 | dev: true 189 | optional: true 190 | 191 | /get-caller-file/2.0.5: 192 | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} 193 | engines: {node: 6.* || 8.* || >= 10.*} 194 | dev: true 195 | 196 | /glob-parent/5.1.2: 197 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 198 | engines: {node: '>= 6'} 199 | dependencies: 200 | is-glob: 4.0.3 201 | dev: true 202 | 203 | /glob/7.2.0: 204 | resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} 205 | dependencies: 206 | fs.realpath: 1.0.0 207 | inflight: 1.0.6 208 | inherits: 2.0.4 209 | minimatch: 3.0.4 210 | once: 1.4.0 211 | path-is-absolute: 1.0.1 212 | dev: true 213 | 214 | /growl/1.10.5: 215 | resolution: {integrity: sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==} 216 | engines: {node: '>=4.x'} 217 | dev: true 218 | 219 | /has-flag/4.0.0: 220 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 221 | engines: {node: '>=8'} 222 | dev: true 223 | 224 | /he/1.2.0: 225 | resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} 226 | hasBin: true 227 | dev: true 228 | 229 | /inflight/1.0.6: 230 | resolution: {integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=} 231 | dependencies: 232 | once: 1.4.0 233 | wrappy: 1.0.2 234 | dev: true 235 | 236 | /inherits/2.0.4: 237 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 238 | dev: true 239 | 240 | /is-binary-path/2.1.0: 241 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 242 | engines: {node: '>=8'} 243 | dependencies: 244 | binary-extensions: 2.2.0 245 | dev: true 246 | 247 | /is-extglob/2.1.1: 248 | resolution: {integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=} 249 | engines: {node: '>=0.10.0'} 250 | dev: true 251 | 252 | /is-fullwidth-code-point/3.0.0: 253 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 254 | engines: {node: '>=8'} 255 | dev: true 256 | 257 | /is-glob/4.0.3: 258 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 259 | engines: {node: '>=0.10.0'} 260 | dependencies: 261 | is-extglob: 2.1.1 262 | dev: true 263 | 264 | /is-number/7.0.0: 265 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 266 | engines: {node: '>=0.12.0'} 267 | dev: true 268 | 269 | /is-plain-obj/2.1.0: 270 | resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} 271 | engines: {node: '>=8'} 272 | dev: true 273 | 274 | /is-unicode-supported/0.1.0: 275 | resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} 276 | engines: {node: '>=10'} 277 | dev: true 278 | 279 | /isexe/2.0.0: 280 | resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=} 281 | dev: true 282 | 283 | /js-yaml/4.1.0: 284 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 285 | hasBin: true 286 | dependencies: 287 | argparse: 2.0.1 288 | dev: true 289 | 290 | /locate-path/6.0.0: 291 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} 292 | engines: {node: '>=10'} 293 | dependencies: 294 | p-locate: 5.0.0 295 | dev: true 296 | 297 | /log-symbols/4.1.0: 298 | resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} 299 | engines: {node: '>=10'} 300 | dependencies: 301 | chalk: 4.1.2 302 | is-unicode-supported: 0.1.0 303 | dev: true 304 | 305 | /minimatch/3.0.4: 306 | resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} 307 | dependencies: 308 | brace-expansion: 1.1.11 309 | dev: true 310 | 311 | /mocha/9.2.0: 312 | resolution: {integrity: sha512-kNn7E8g2SzVcq0a77dkphPsDSN7P+iYkqE0ZsGCYWRsoiKjOt+NvXfaagik8vuDa6W5Zw3qxe8Jfpt5qKf+6/Q==} 313 | engines: {node: '>= 12.0.0'} 314 | hasBin: true 315 | dependencies: 316 | '@ungap/promise-all-settled': 1.1.2 317 | ansi-colors: 4.1.1 318 | browser-stdout: 1.3.1 319 | chokidar: 3.5.3 320 | debug: 4.3.3_supports-color@8.1.1 321 | diff: 5.0.0 322 | escape-string-regexp: 4.0.0 323 | find-up: 5.0.0 324 | glob: 7.2.0 325 | growl: 1.10.5 326 | he: 1.2.0 327 | js-yaml: 4.1.0 328 | log-symbols: 4.1.0 329 | minimatch: 3.0.4 330 | ms: 2.1.3 331 | nanoid: 3.2.0 332 | serialize-javascript: 6.0.0 333 | strip-json-comments: 3.1.1 334 | supports-color: 8.1.1 335 | which: 2.0.2 336 | workerpool: 6.2.0 337 | yargs: 16.2.0 338 | yargs-parser: 20.2.4 339 | yargs-unparser: 2.0.0 340 | dev: true 341 | 342 | /ms/2.1.2: 343 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 344 | dev: true 345 | 346 | /ms/2.1.3: 347 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 348 | dev: true 349 | 350 | /nanoid/3.2.0: 351 | resolution: {integrity: sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==} 352 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 353 | hasBin: true 354 | dev: true 355 | 356 | /normalize-path/3.0.0: 357 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 358 | engines: {node: '>=0.10.0'} 359 | dev: true 360 | 361 | /once/1.4.0: 362 | resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=} 363 | dependencies: 364 | wrappy: 1.0.2 365 | dev: true 366 | 367 | /p-limit/3.1.0: 368 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 369 | engines: {node: '>=10'} 370 | dependencies: 371 | yocto-queue: 0.1.0 372 | dev: true 373 | 374 | /p-locate/5.0.0: 375 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 376 | engines: {node: '>=10'} 377 | dependencies: 378 | p-limit: 3.1.0 379 | dev: true 380 | 381 | /path-exists/4.0.0: 382 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 383 | engines: {node: '>=8'} 384 | dev: true 385 | 386 | /path-is-absolute/1.0.1: 387 | resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=} 388 | engines: {node: '>=0.10.0'} 389 | dev: true 390 | 391 | /picomatch/2.3.1: 392 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 393 | engines: {node: '>=8.6'} 394 | dev: true 395 | 396 | /randombytes/2.1.0: 397 | resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} 398 | dependencies: 399 | safe-buffer: 5.2.1 400 | dev: true 401 | 402 | /readdirp/3.6.0: 403 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 404 | engines: {node: '>=8.10.0'} 405 | dependencies: 406 | picomatch: 2.3.1 407 | dev: true 408 | 409 | /require-directory/2.1.1: 410 | resolution: {integrity: sha1-jGStX9MNqxyXbiNE/+f3kqam30I=} 411 | engines: {node: '>=0.10.0'} 412 | dev: true 413 | 414 | /safe-buffer/5.2.1: 415 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 416 | dev: true 417 | 418 | /serialize-javascript/6.0.0: 419 | resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} 420 | dependencies: 421 | randombytes: 2.1.0 422 | dev: true 423 | 424 | /string-width/4.2.3: 425 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 426 | engines: {node: '>=8'} 427 | dependencies: 428 | emoji-regex: 8.0.0 429 | is-fullwidth-code-point: 3.0.0 430 | strip-ansi: 6.0.1 431 | dev: true 432 | 433 | /strip-ansi/6.0.1: 434 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 435 | engines: {node: '>=8'} 436 | dependencies: 437 | ansi-regex: 5.0.1 438 | dev: true 439 | 440 | /strip-json-comments/3.1.1: 441 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 442 | engines: {node: '>=8'} 443 | dev: true 444 | 445 | /supports-color/7.2.0: 446 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 447 | engines: {node: '>=8'} 448 | dependencies: 449 | has-flag: 4.0.0 450 | dev: true 451 | 452 | /supports-color/8.1.1: 453 | resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} 454 | engines: {node: '>=10'} 455 | dependencies: 456 | has-flag: 4.0.0 457 | dev: true 458 | 459 | /to-regex-range/5.0.1: 460 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 461 | engines: {node: '>=8.0'} 462 | dependencies: 463 | is-number: 7.0.0 464 | dev: true 465 | 466 | /which/2.0.2: 467 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 468 | engines: {node: '>= 8'} 469 | hasBin: true 470 | dependencies: 471 | isexe: 2.0.0 472 | dev: true 473 | 474 | /workerpool/6.2.0: 475 | resolution: {integrity: sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==} 476 | dev: true 477 | 478 | /wrap-ansi/7.0.0: 479 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 480 | engines: {node: '>=10'} 481 | dependencies: 482 | ansi-styles: 4.3.0 483 | string-width: 4.2.3 484 | strip-ansi: 6.0.1 485 | dev: true 486 | 487 | /wrappy/1.0.2: 488 | resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=} 489 | dev: true 490 | 491 | /y18n/5.0.8: 492 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} 493 | engines: {node: '>=10'} 494 | dev: true 495 | 496 | /yargs-parser/20.2.4: 497 | resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} 498 | engines: {node: '>=10'} 499 | dev: true 500 | 501 | /yargs-unparser/2.0.0: 502 | resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} 503 | engines: {node: '>=10'} 504 | dependencies: 505 | camelcase: 6.3.0 506 | decamelize: 4.0.0 507 | flat: 5.0.2 508 | is-plain-obj: 2.1.0 509 | dev: true 510 | 511 | /yargs/16.2.0: 512 | resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} 513 | engines: {node: '>=10'} 514 | dependencies: 515 | cliui: 7.0.4 516 | escalade: 3.1.1 517 | get-caller-file: 2.0.5 518 | require-directory: 2.1.1 519 | string-width: 4.2.3 520 | y18n: 5.0.8 521 | yargs-parser: 20.2.4 522 | dev: true 523 | 524 | /yocto-queue/0.1.0: 525 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 526 | engines: {node: '>=10'} 527 | dev: true 528 | -------------------------------------------------------------------------------- /source-map-sharp.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | SourceMapSharp 5 | Source Map Sharp sourcemap generation tool 6 | netstandard2.0 7 | 1.0.9 8 | 1.0.9 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /source-map-sharp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "source-map-sharp", "source-map-sharp.fsproj", "{1D809047-0E41-4C6B-9191-CDCA18AD8B2C}" 4 | EndProject 5 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Tests", "Tests\Tests.fsproj", "{404823EE-969B-4148-AE36-2BC09FE3C201}" 6 | EndProject 7 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Benchmarks", "Benchmarks\Benchmarks.fsproj", "{CF8855C0-D02D-4C7F-B72B-CBD08ADCD687}" 8 | EndProject 9 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Tests.Fable", "Tests.Fable\Tests.Fable.fsproj", "{BFFCA172-AD6B-4933-ACF2-F251CC3F507E}" 10 | EndProject 11 | Global 12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 13 | Debug|Any CPU = Debug|Any CPU 14 | Release|Any CPU = Release|Any CPU 15 | EndGlobalSection 16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 | {1D809047-0E41-4C6B-9191-CDCA18AD8B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {1D809047-0E41-4C6B-9191-CDCA18AD8B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {1D809047-0E41-4C6B-9191-CDCA18AD8B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {1D809047-0E41-4C6B-9191-CDCA18AD8B2C}.Release|Any CPU.Build.0 = Release|Any CPU 21 | {404823EE-969B-4148-AE36-2BC09FE3C201}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {404823EE-969B-4148-AE36-2BC09FE3C201}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {404823EE-969B-4148-AE36-2BC09FE3C201}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {404823EE-969B-4148-AE36-2BC09FE3C201}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {CF8855C0-D02D-4C7F-B72B-CBD08ADCD687}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {CF8855C0-D02D-4C7F-B72B-CBD08ADCD687}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {CF8855C0-D02D-4C7F-B72B-CBD08ADCD687}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {CF8855C0-D02D-4C7F-B72B-CBD08ADCD687}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {BFFCA172-AD6B-4933-ACF2-F251CC3F507E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {BFFCA172-AD6B-4933-ACF2-F251CC3F507E}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {BFFCA172-AD6B-4933-ACF2-F251CC3F507E}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {BFFCA172-AD6B-4933-ACF2-F251CC3F507E}.Release|Any CPU.Build.0 = Release|Any CPU 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /src/ArraySet.fs: -------------------------------------------------------------------------------- 1 | namespace SourceMapSharp 2 | 3 | open System.Collections.Generic 4 | 5 | type ArraySet<'T when 'T : equality>() = 6 | let _array = new ResizeArray<'T>() 7 | let _set = Dictionary<'T,int>() 8 | member _.Size() = _set.Count 9 | member _.Has(aStr:'T) = 10 | _set.ContainsKey(aStr) 11 | member _.indexOf(aStr: 'T) = 12 | if _set.ContainsKey(aStr) then Some _set.[aStr] else None 13 | member _.Add(aStr: 'T,aAllowDuplicates:bool) = 14 | let isDuplicate = _array.Contains aStr 15 | let idx = _set.Count 16 | if not isDuplicate || aAllowDuplicates then 17 | _array.Add(aStr) 18 | if not isDuplicate then 19 | _set.[aStr] <- idx 20 | member _.At(aIdx: int) = 21 | if aIdx >= 0 && aIdx < _array.Count then 22 | Some _array.[aIdx] 23 | else None 24 | member _.ToArray() = _array 25 | static member fromArray(aArray: 'T [], allowDuplicates) = 26 | let s = new ArraySet<'T>() 27 | for i in aArray do 28 | s.Add(i,allowDuplicates) 29 | s 30 | -------------------------------------------------------------------------------- /src/Base64VLQ.fs: -------------------------------------------------------------------------------- 1 | namespace SourceMapSharp 2 | 3 | open System 4 | #if !FABLE_COMPILER 5 | open System.IO 6 | open System.Runtime.Serialization 7 | #endif 8 | 9 | // Original C# Code 10 | // https://github.com/madskristensen/WebEssentials2013/blob/96d37799/EditorExtensions/Shared/Helpers/Base64VLQ.cs 11 | [] 12 | type VlqException() = 13 | inherit Exception() 14 | new(message : string) = 15 | (VlqException ()) 16 | then 17 | () 18 | new(message : string, innerException : Exception) = 19 | (VlqException ()) 20 | then 21 | () 22 | #if !FABLE_COMPILER 23 | new(info : SerializationInfo, context : StreamingContext) = 24 | (VlqException ()) 25 | then 26 | () 27 | #endif 28 | 29 | module Base64 = 30 | let intToCharMap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".ToCharArray() 31 | let base64Encode(c:int) = 32 | if (0 <= c && c < intToCharMap.Length) then 33 | intToCharMap.[c] 34 | else 35 | #if FABLE_COMPILER 36 | failwith $"Must be between 0 and 63: {c}" 37 | #else 38 | raise (VlqException("Must be between 0 and 63: " + string c) :> System.Exception) 39 | #endif 40 | 41 | 42 | let base64Decode(c: char) = 43 | let index = Array.IndexOf(intToCharMap,c) 44 | if index > -1 then index 45 | else 46 | #if FABLE_COMPILER 47 | failwith $"Not a valid base 64 digit: {c}" 48 | #else 49 | raise (VlqException("Not a valid base 64 digit: " + string c)) 50 | #endif 51 | 52 | 53 | type Base64Vlq() = 54 | // A single base 64 digit can contain 6 bits of data. For the base 64 variable 55 | // length quantities we use in the source map spec, the first bit is the sign, 56 | // the next four bits are the actual value, and the 6th bit is the 57 | // continuation bit. The continuation bit tells us whether there are more 58 | // digits in this value following this digit. 59 | // 60 | // Continuation 61 | // | Sign 62 | // | | 63 | // V V 64 | // 101011 65 | static member VLQ_BASE_SHIFT = 5 66 | // binary: 100000 67 | static member VLQ_BASE = 1 <<< Base64Vlq.VLQ_BASE_SHIFT 68 | // binary: 011111 69 | static member VLQ_BASE_MASK = Base64Vlq.VLQ_BASE - 1 70 | // binary: 100000 71 | static member VLQ_CONTINUATION_BIT = Base64Vlq.VLQ_BASE 72 | 73 | static member private IsMappingSeparator(ch : int) = 74 | ch = (int ',') || ch = (int ';') 75 | 76 | #if !FABLE_COMPILER 77 | static member private GetName(index : int, basePath : string, sources : string[]) = 78 | if sources.Length = 0 79 | then Some (String.Empty) 80 | elif sources.Length > index 81 | then Some (Path.GetFullPath (Path.Combine (basePath, sources.[index]))) 82 | else None 83 | #endif 84 | 85 | // Converts from a two-complement value to a value where the sign bit is 86 | // placed in the least significant bit. For example, as decimals: 87 | // 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) 88 | // 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) 89 | static member private ToVLQSigned(value : int) = 90 | if value < 0 91 | then (-value <<< 1) + 1 92 | else (value <<< 1) + 0 93 | 94 | // Converts to a two-complement value from a value where the sign bit is 95 | // is placed in the least significant bit. For example, as decimals: 96 | // 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 97 | // 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 98 | static member private FromVLQSigned(value : int) = 99 | let mutable isNegative = value &&& 1 = 1 100 | let mutable shifted = value >>> 1 101 | if isNegative 102 | then -shifted 103 | else shifted 104 | 105 | static member Encode(number : int) = 106 | let mutable encoded = new System.Text.StringBuilder() 107 | let mutable (digit : int) = Unchecked.defaultof 108 | let mutable vlq = Base64Vlq.ToVLQSigned (number) 109 | // isZeroCase is needed because F# doesn't have 'do {} while' 110 | let mutable isZeroCase = number = 0 111 | while vlq > 0 || isZeroCase do 112 | isZeroCase <- false 113 | digit <- vlq &&& Base64Vlq.VLQ_BASE_MASK 114 | vlq <- vlq >>> Base64Vlq.VLQ_BASE_SHIFT 115 | if vlq > 0 then 116 | // There are still more digits in this value, so we must make sure the 117 | // continuation bit is marked. 118 | digit <- digit ||| Base64Vlq.VLQ_CONTINUATION_BIT 119 | encoded.Append(Base64.base64Encode(digit)) |> ignore 120 | encoded.ToString () 121 | 122 | #if !FABLE_COMPILER 123 | static member VlqDecode(stream : TextReader) = 124 | let mutable result = 0 125 | let mutable shift = 0 126 | let mutable continuation = true 127 | let mutable (digit : int) = 0 128 | while continuation do 129 | if stream.Peek() = -1 then 130 | raise (VlqException("Expected more digits in base 64 VLQ value.")) 131 | digit <- Base64.base64Decode(char (stream.Read())) 132 | continuation <- (digit &&& Base64Vlq.VLQ_CONTINUATION_BIT) <> 0 133 | digit <- digit &&& Base64Vlq.VLQ_BASE_MASK 134 | result <- result + (digit <<< shift) 135 | shift <- shift + Base64Vlq.VLQ_BASE_SHIFT 136 | Base64Vlq.FromVLQSigned (result) 137 | #endif 138 | -------------------------------------------------------------------------------- /src/FSharpConverters.fs: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/mbuhot/c224f15e0266adf5ba8ca4e882f88a75 2 | 3 | namespace System.Text.Json 4 | 5 | #if !FABLE_COMPILER 6 | 7 | open System 8 | open System.Collections.Generic 9 | open System.Text.Json.Serialization 10 | 11 | // Converts Option to/from JSON by projecting to null or T 12 | type OptionValueConverter<'T>() = 13 | inherit JsonConverter<'T option>() 14 | 15 | override this.Read (reader: byref, _typ: Type, options: JsonSerializerOptions) = 16 | match reader.TokenType with 17 | | JsonTokenType.Null -> None 18 | | _ -> Some <| JsonSerializer.Deserialize<'T>(&reader, options) 19 | 20 | override this.Write (writer: Utf8JsonWriter, value: 'T option, options: JsonSerializerOptions) = 21 | match value with 22 | | None -> writer.WriteNullValue () 23 | | Some value -> JsonSerializer.Serialize(writer, value, options) 24 | 25 | // Instantiates the correct OptionValueConverter 26 | type OptionConverter() = 27 | inherit JsonConverterFactory() 28 | override this.CanConvert(t: Type) : bool = 29 | t.IsGenericType && 30 | t.GetGenericTypeDefinition() = typedefof> 31 | 32 | override this.CreateConverter(typeToConvert: Type, 33 | _options: JsonSerializerOptions) : JsonConverter = 34 | let typ = typeToConvert.GetGenericArguments() |> Array.head 35 | let converterType = typedefof>.MakeGenericType(typ) 36 | Activator.CreateInstance(converterType) :?> JsonConverter 37 | 38 | // Converts Map to/from JSON by projecting to Dictionary 39 | type MapValueConverter<'K, 'V when 'K : comparison>() = 40 | inherit JsonConverter>() 41 | 42 | override this.Read (reader: byref, _typ: Type, options: JsonSerializerOptions) = 43 | JsonSerializer.Deserialize>(&reader, options) 44 | |> Seq.map (|KeyValue|) 45 | |> Map.ofSeq 46 | 47 | override this.Write (writer: Utf8JsonWriter, value: Map<'K, 'V>, options: JsonSerializerOptions) = 48 | let dictionary = Dictionary<'K, 'V>() 49 | value |> Map.iter (fun k v -> dictionary.Add(k, v)) 50 | JsonSerializer.Serialize(writer, dictionary, options) 51 | 52 | // Instantiates the correct MapValueConverter 53 | type MapConverter() = 54 | inherit JsonConverterFactory() 55 | override this.CanConvert(t: Type) : bool = 56 | t.IsGenericType && 57 | List.contains (t.GetGenericTypeDefinition()) [typedefof>; typedefof>] 58 | 59 | override this.CreateConverter(typeToConvert: Type, 60 | _options: JsonSerializerOptions) : JsonConverter = 61 | let typArgs = typeToConvert.GetGenericArguments() 62 | let converterType = typedefof>.MakeGenericType(typArgs) 63 | Activator.CreateInstance(converterType) :?> JsonConverter 64 | 65 | // Converts List to/from JSON by projecting to IEnumerable 66 | type ListValueConverter<'T>() = 67 | inherit JsonConverter<'T list>() 68 | 69 | override this.Read (reader: byref, _typ: Type, options: JsonSerializerOptions) = 70 | JsonSerializer.Deserialize<'T seq>(&reader, options) 71 | |> List.ofSeq 72 | 73 | override this.Write (writer: Utf8JsonWriter, value: 'T list, options: JsonSerializerOptions) = 74 | JsonSerializer.Serialize(writer, (List.toSeq value), options) 75 | 76 | // Instantiates the correct ListValueConverter 77 | type ListConverter() = 78 | inherit JsonConverterFactory() 79 | override this.CanConvert(t: Type) : bool = 80 | t.IsGenericType && 81 | List.contains (t.GetGenericTypeDefinition()) [typedefof>; typedefof>] 82 | 83 | override this.CreateConverter(typeToConvert: Type, 84 | _options: JsonSerializerOptions) : JsonConverter = 85 | let typArgs = typeToConvert.GetGenericArguments() 86 | let converterType = typedefof>.MakeGenericType(typArgs) 87 | Activator.CreateInstance(converterType) :?> JsonConverter 88 | 89 | module FSharpConverters = 90 | let Options = 91 | let opt = JsonSerializerOptions() 92 | opt.Converters.Add(new OptionConverter()) |> ignore 93 | opt.Converters.Add(new MapConverter()) |> ignore 94 | opt.Converters.Add(new ListConverter()) |> ignore 95 | opt 96 | 97 | #endif //!FABLE_COMPILER 98 | -------------------------------------------------------------------------------- /src/MappingList.fs: -------------------------------------------------------------------------------- 1 | namespace SourceMapSharp 2 | 3 | open SourceMapSharp.Util 4 | 5 | module MappingList = 6 | 7 | let inline generatedPositionAfter (mappingA:Mapping) (mappingB:Mapping) = 8 | let lineA = mappingA.Generated.line 9 | let lineB = mappingB.Generated.line 10 | let columnA = mappingA.Generated.column 11 | let columnB = mappingB.Generated.column 12 | lineB > lineA 13 | || (lineB = lineA && columnB >= columnA) 14 | || compareByGeneratedPositionsInflated mappingA mappingB <= 0 15 | 16 | type MappingList() = 17 | let _array = ResizeArray() 18 | let mutable _sorted = true 19 | let mutable _last = {Generated = {line = -1; column = 0};Original=None;Source = None;Name=None} 20 | 21 | member _.UnsortedForEach(aCallback) = 22 | _array.ForEach(aCallback) 23 | 24 | member _.Add(aMapping: Mapping) = 25 | if MappingList.generatedPositionAfter _last aMapping then 26 | _last <- aMapping 27 | _array.Add(aMapping) 28 | else 29 | _sorted <- false 30 | _array.Add(aMapping) 31 | 32 | member _.ToArray() = 33 | if not _sorted then 34 | _array.Sort(sharedMappingComparer) 35 | _sorted <- true 36 | _array 37 | -------------------------------------------------------------------------------- /src/SourceMapConsumer.fs: -------------------------------------------------------------------------------- 1 | namespace SourceMapSharp 2 | 3 | open System.Collections.Generic 4 | open SourceMapSharp.Util 5 | 6 | module SourceMapConsumer = 7 | let version = 3 8 | let GENERATED_ORDER = 1 9 | let ORIGINAL_ORDER = 2 10 | let GREATEST_LOWER_BOUND = 1 11 | let LEAST_UPPER_BOUND = 2 12 | 13 | 14 | type BasicSourceMapConsumer(sourceMap: SourceGeneratorJSON, sourceMapUrl: string) = 15 | do 16 | if SourceMapConsumer.version <> sourceMap.version 17 | then failwithf "Unsupported version %i" sourceMap.version 18 | 19 | let _version = sourceMap.version 20 | 21 | let _mappings = sourceMap.mappings 22 | // Don't loosen up on 'names' like in JS, because no Sass problem 23 | let _sourceLookupCache = Dictionary<_,_>() 24 | // Pass `true` below to allow duplicate names and sources. While source maps 25 | // are intended to be compressed and deduplicated, the TypeScript compiler 26 | // sometimes generates source maps with duplicates in them. See Github issue 27 | // #72 and bugzil.la/889492. 28 | let _names = ArraySet.fromArray(sourceMap.names |> Array.ofSeq, true) 29 | let _sources = ArraySet.fromArray(sourceMap.sources |> Array.ofSeq, true) 30 | let sourceRoot = sourceMap.sourceRoot |> Option.defaultValue "" 31 | let sourceUrls = 32 | sourceMap.sources 33 | |> Seq.map (fun s -> computeSourceUrl sourceRoot s sourceMapUrl) 34 | |> Array.ofSeq 35 | let _absoluteSources = ArraySet.fromArray(sourceUrls, true) 36 | let sourcesContent = sourceMap.sourcesContent |> Option.defaultValue Seq.empty 37 | member val _computedColumnSpans = false 38 | member val _mappingsPtr = 0 39 | 40 | member _.sources() = _absoluteSources.ToArray() 41 | -------------------------------------------------------------------------------- /src/SourceMapGenerator.fs: -------------------------------------------------------------------------------- 1 | namespace SourceMapSharp 2 | 3 | open System.Collections.Generic 4 | open SourceMapSharp.Util 5 | 6 | 7 | // An instance of the SourceMapGenerator represents a source map which is 8 | // being built incrementally. You may pass an object with the following 9 | // properties: 10 | // - file: The filename of the generated source. 11 | // - sourceRoot: A root for all relative URLs in this source map. 12 | 13 | 14 | type SourceMapGenerator(?skipValidation:bool, ?file:string, ?sourceRoot:string) = 15 | 16 | let _file = file 17 | let _sourceRoot = sourceRoot 18 | let _skipValidation = defaultArg skipValidation false 19 | let _names = ArraySet() 20 | let _mappings = MappingList() 21 | member val _sourcesContents = Dictionary() 22 | member val _sources = ArraySet() 23 | 24 | static member version = 3 25 | // A mapping can have one of the three levels of data: 26 | // 1. Just the generated position. 27 | // 2. The Generated position, original position, and original source. 28 | // 3. Generated and original position, original source, as well as a name 29 | // token. 30 | 31 | // To maintain consistency, we validate that any new mapping being added falls 32 | // in to one of these categories. 33 | 34 | static member ValidateMapping(generated: MappingIndex,original: MappingIndex option,source: string option,name: string option) = 35 | // we don't need to check original.line & original.column === "number" because of F# type checks 36 | let mutable isInvalid = true 37 | if generated.line > 0 && generated.column >=0 && original.IsNone && source.IsNone && name.IsNone then 38 | isInvalid <- false 39 | 40 | elif generated.line > 0 && generated.column >=0 41 | && original.IsSome && original.Value.line > 0 && original.Value.column >= 0 42 | && source.IsSome then 43 | isInvalid <- false 44 | 45 | if isInvalid then 46 | let options = {|generated = generated; source=source; original=original; name=name|} 47 | let err = sprintf "Invalid mapping: %A" options 48 | raise (System.Exception(err)) 49 | 50 | // Add a single mapping from original source line and column to the generated 51 | // source's line and column for this source map being created. The mapping 52 | // object should have the following properties: 53 | // - generated: An object with the generated line and column positions. 54 | // - original: An object with the original line and column positions. 55 | // - source: The original source file (relative to the sourceRoot). 56 | // - name: An optional original token name for this mapping. 57 | // 58 | member this.AddMapping(generated: MappingIndex,?original: MappingIndex,?source: string,?name: string) = 59 | if not _skipValidation then 60 | do SourceMapGenerator.ValidateMapping(generated,original,source,name) 61 | 62 | if source.IsSome then 63 | if not (this._sources.Has(source.Value)) then 64 | this._sources.Add(source.Value, false) 65 | 66 | if name.IsSome then 67 | if not (_names.Has(name.Value)) then 68 | _names.Add(name.Value, false) 69 | 70 | _mappings.Add({Generated=generated;Original=original;Source=source;Name=name}) 71 | 72 | member this.GenerateSourcesContent(aSources, aSourceRoot: string option) = 73 | aSources 74 | |> Seq.map (fun source -> 75 | if this._sourcesContents.Keys.Count = 0 then 76 | None 77 | else 78 | let mutable s = source 79 | if aSourceRoot.IsSome then 80 | s <- getRelativePath(_sourceRoot.Value,source) 81 | // don't need `util.toSetString(source)` in F# 82 | if this._sourcesContents.ContainsKey(s) then 83 | Some <| this._sourcesContents.[s] 84 | else 85 | None 86 | ) 87 | 88 | member this.SetSourceContent(aSourceFile, aSourceContent: string option) = 89 | let mutable source = aSourceFile 90 | if _sourceRoot.IsSome then 91 | source <- getRelativePath(_sourceRoot.Value,source) 92 | if aSourceContent.IsSome then 93 | // Add the source content to the _sourcesContents map. 94 | // We don't need to create a new _sourceContents 95 | // because it's always initialized 96 | this._sourcesContents.[source] <- aSourceContent.Value 97 | elif this._sourcesContents.Keys.Count > 0 then 98 | // Remove the source file from the _sourcesContents map. 99 | // We don't need to set _sourcesContents to null, 100 | // because we only use `.Keys.Count` checks 101 | this._sourcesContents.Remove(source) |> ignore 102 | 103 | member this.toJSON() = 104 | let version,sources,names,mappings = (SourceMapGenerator.version, 105 | this._sources.ToArray(), 106 | _names.ToArray(), 107 | this.SerializeMappings() 108 | ) 109 | let sourcesContent = 110 | if this._sourcesContents.Keys.Count > 0 then 111 | Some(this.GenerateSourcesContent(sources,_sourceRoot)) 112 | else 113 | None 114 | 115 | { version=version 116 | sources=sources 117 | names=names 118 | mappings=mappings 119 | file=_file 120 | sourcesContent=sourcesContent 121 | sourceRoot=_sourceRoot } 122 | 123 | #if !FABLE_COMPILER 124 | // Render the source map being generated to a string. 125 | override this.ToString() = this.toJSON().Serialize() 126 | #endif 127 | 128 | // Serialize the accumulated mappings in to the stream of base 64 VLQs 129 | // specified by the source map format. 130 | member this.SerializeMappings() = 131 | let mutable previousGeneratedColumn = 0 132 | let mutable previousGeneratedLine = 1 133 | let mutable previousOriginalColumn = 0 134 | let mutable previousOriginalLine = 0 135 | let mutable previousName = 0; 136 | let mutable previousSource = 0 137 | let result = System.Text.StringBuilder() 138 | let next = System.Text.StringBuilder() 139 | let mutable nameIdx = 0 140 | let mutable sourceIdx = 0 141 | let mappings = _mappings.ToArray() 142 | for i in [0..mappings.Count - 1] do 143 | // hack for 'continue' keyword in JS 144 | let mutable shouldContinue = false 145 | let mapping = mappings.[i] 146 | next.Clear() |> ignore 147 | if mapping.Generated.line <> previousGeneratedLine then 148 | previousGeneratedColumn <- 0 149 | while mapping.Generated.line <> previousGeneratedLine do 150 | next.Append(";") |> ignore 151 | previousGeneratedLine <- previousGeneratedLine + 1 152 | elif i > 0 then 153 | let compared = compareByGeneratedPositionsInflated mapping mappings.[i-1] 154 | if compared = 0 then 155 | // JS has 'continue' here, which we're emulating with a mutable bool 156 | shouldContinue <- true 157 | else 158 | next.Append(",") |> ignore 159 | if not shouldContinue then 160 | next.Append(Base64Vlq.Encode (mapping.Generated.column - previousGeneratedColumn)) |> ignore 161 | previousGeneratedColumn <- mapping.Generated.column 162 | if mapping.Source.IsSome then 163 | mapping.Source 164 | |> Option.bind (this._sources.indexOf) 165 | |> Option.iter (fun indexOfMappingSource -> 166 | sourceIdx <- indexOfMappingSource 167 | next.Append(Base64Vlq.Encode (sourceIdx - previousSource)) |> ignore 168 | previousSource <- sourceIdx 169 | ) 170 | // lines are stored 0-based in SourceMap spec version 3 171 | mapping.Original 172 | |> Option.iter (fun original -> 173 | next.Append(Base64Vlq.Encode (original.line - 1 - previousOriginalLine)) |> ignore 174 | previousOriginalLine <- original.line - 1 175 | 176 | next.Append(Base64Vlq.Encode (original.column - previousOriginalColumn)) |> ignore 177 | previousOriginalColumn <- original.column 178 | ) 179 | 180 | if mapping.Name.IsSome then 181 | mapping.Name 182 | |> Option.bind (_names.indexOf) 183 | |> Option.iter (fun indexOfMappingName -> 184 | nameIdx <- indexOfMappingName 185 | next.Append(Base64Vlq.Encode (nameIdx - previousName)) |> ignore 186 | previousName <- nameIdx 187 | ) 188 | result.Append(next.ToString()) |> ignore 189 | result.ToString() -------------------------------------------------------------------------------- /src/SourceNode.fs: -------------------------------------------------------------------------------- 1 | namespace SourceMapSharp 2 | 3 | open System.Text.RegularExpressions 4 | open System.Collections.Generic 5 | 6 | module SourceNode = 7 | let REGEX_NEWLINE = Regex @"(\r?\n)" 8 | // Newline character code for charCodeAt() comparisons 9 | let NEWLINE_CODE = 10 10 | 11 | //We don't need `isSourceNode` since we have DU's 12 | 13 | type SourceMappingOriginal = { 14 | line: int option 15 | column: int option 16 | Source: string option 17 | Name: string option 18 | } 19 | 20 | type SourceChunk = 21 | | ChunkS of string 22 | | ChunkArrS of string[] 23 | | ChunkArrSN of SourceNode[] 24 | 25 | and SourceNodeChild = 26 | | S of string 27 | | SN of SourceNode 28 | override this.ToString() = 29 | match this with 30 | | S s -> s 31 | | SN sn -> sn.ToString() 32 | 33 | // SourceNodes provide a way to abstract over interpolating/concatenating 34 | // snippets of generated JavaScript source code while maintaining the line and 35 | // column information associated with the original source code. 36 | and SourceNode(?_line: int, ?_column: int, ?_source: string, ?_chunks: SourceChunk[], ?_name: string) as this = 37 | let addChunkToArray (chunk:SourceChunk,arr: ResizeArray) = 38 | match chunk with 39 | | ChunkS str -> arr.Add(S str) 40 | | ChunkArrS arrs -> arrs |> Array.iter (fun x -> arr.Add(S x)) 41 | | ChunkArrSN arrsn -> arrsn |> Array.iter (fun x -> arr.Add(SN x)) 42 | let mutable _children = 43 | let arr = ResizeArray() 44 | match _chunks with 45 | | Some chunks -> 46 | chunks |> Array.iter (fun chunk -> addChunkToArray(chunk,arr)) 47 | arr 48 | | None -> arr 49 | 50 | member val line = _line 51 | member val column = _column 52 | member val source = _source 53 | member val name = _name 54 | member this.children 55 | with get() = _children 56 | and set(value) = _children <- value 57 | member val sourcesContents = Dictionary() 58 | 59 | // Add a chunk of generated JS to this source node. 60 | member _.Add(chunk: SourceChunk) : SourceNode = 61 | addChunkToArray(chunk,this.children) 62 | this 63 | // Add a chunk of generated JS to the beginning of this source node. 64 | member _.Prepend(chunk: SourceChunk) = 65 | match chunk with 66 | | ChunkS str -> this.children.Insert(0,S str) 67 | | ChunkArrS arrs -> this.children.InsertRange(0, arrs |> Array.map S) 68 | | ChunkArrSN arrsn -> this.children.InsertRange(0, arrsn |> Array.map SN) 69 | this 70 | member _.Prepend(chunks: SourceChunk[]) = 71 | for i = chunks.Length - 1 downto 0 do 72 | this.Prepend(chunks.[i]) |> ignore 73 | this 74 | // Walk over the tree of JS snippets in this node and its children. The 75 | // walking function is called once for each snippet of JS and is passed that 76 | // snippet and the its original associated source's line/column location. 77 | member _.Walk(fn: string -> SourceMappingOriginal -> unit) = 78 | for chunk in this.children do 79 | match chunk with 80 | | S str -> fn str {line = this.line;column=this.column;Source=this.source;Name=this.name} 81 | | SN sn -> sn.Walk(fn) 82 | 83 | // Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between 84 | // each of `this.children`. 85 | member _.Join(sep: string) = 86 | if this.children.Count > 0 then 87 | let newChildren = ResizeArray() 88 | let len = this.children.Count 89 | for i = 0 to len - 2 do 90 | newChildren.Add(this.children.[i]) 91 | newChildren.Add(S sep) 92 | newChildren.Add(this.children.[len - 1]) 93 | this.children <- newChildren 94 | this 95 | 96 | // Return the string representation of this source node. Walks over the tree 97 | // and concatenates all the various snippets together to one string. 98 | override _.ToString() = 99 | let sb = System.Text.StringBuilder() 100 | this.Walk(fun s _ -> sb.Append(s) |> ignore) 101 | sb.ToString() 102 | 103 | // Call String.prototype.replace on the very right-most source snippet. Useful 104 | // for trimming whitespace from the end of a source node, etc. 105 | member _.ReplaceRight(pattern:string, replacement:string) = 106 | let lastChild = this.children |> Seq.tryLast 107 | match lastChild with 108 | | Some (SN sn) -> sn.ReplaceRight(pattern, replacement) 109 | | Some (S str) -> 110 | this.children.[this.children.Count - 1] <- (str.Replace(pattern, replacement) |> S) 111 | this 112 | | None -> 113 | this.children.Add("".Replace(pattern,replacement) |> S) 114 | this 115 | 116 | // Set the source content for a source file. This will be added to the SourceMapGenerator 117 | // in the sourcesContent field. 118 | member _.SetSourceContent(file,content) = 119 | this.sourcesContents.[file] <- content 120 | 121 | // Walk over the tree of SourceNodes. The walking function is called for each 122 | // source file content and is passed the filename and source content. 123 | member _.WalkSourceContents fn = 124 | for child in this.children do 125 | match child with 126 | | SN sn -> sn.WalkSourceContents(fn) 127 | | _ -> () 128 | this.sourcesContents |> Seq.iter (fun kvp -> fn(kvp.Key,kvp.Value)) 129 | 130 | // Returns the string representation of this source node along with a source 131 | // map. 132 | member _.ToStringWithSourceMap(?skipValidation:bool,?file:string,?sourceRoot:string) = 133 | let map = 134 | match (skipValidation,file,sourceRoot) with 135 | | Some x, Some y, Some z -> SourceMapGenerator(x, y, z) 136 | | Some x, Some y, None -> SourceMapGenerator(skipValidation = x,file = y) 137 | | Some x, None, Some z -> SourceMapGenerator(skipValidation = x, sourceRoot = z) 138 | | None, Some y, Some z -> SourceMapGenerator(file = y, sourceRoot = z) 139 | | None, Some y, None -> SourceMapGenerator (file = y) 140 | | Some x, None, None -> SourceMapGenerator(skipValidation = x) 141 | | None, None, Some z -> SourceMapGenerator(sourceRoot = z) 142 | | None, None, None -> SourceMapGenerator() 143 | let mutable generatedCode = System.Text.StringBuilder() 144 | let mutable generatedLine = 1 145 | let mutable generatedColumn = 0 146 | let mutable sourceMappingActive = false 147 | let mutable lastOriginalSource = None 148 | let mutable lastOriginalLine = None 149 | let mutable lastOriginalColumn = None 150 | let mutable lastOriginalName = None 151 | this.Walk(fun chunk original -> 152 | generatedCode.Append(chunk) |> ignore 153 | if original.Source.IsSome && original.line.IsSome && original.column.IsSome then 154 | if lastOriginalSource <> original.Source || 155 | lastOriginalLine <> original.line || 156 | lastOriginalColumn <> original.column || 157 | lastOriginalName <> original.Name then 158 | let _generated: Util.MappingIndex = {line = generatedLine; column = generatedColumn} 159 | let _original: Util.MappingIndex = {line = original.line.Value; column = original.column.Value} 160 | match original.Name with 161 | | Some n -> map.AddMapping(_generated, _original, original.Source.Value, n) 162 | | None -> map.AddMapping(_generated, _original, original.Source.Value) 163 | lastOriginalSource <- original.Source 164 | lastOriginalLine <- original.line 165 | lastOriginalColumn <- original.column 166 | lastOriginalName <- original.Name 167 | sourceMappingActive <- true 168 | elif sourceMappingActive then 169 | let _generated: Util.MappingIndex = {line = generatedLine; column = generatedColumn} 170 | map.AddMapping(_generated) 171 | lastOriginalSource <- None 172 | sourceMappingActive <- false 173 | 174 | for idx in [0..chunk.Length-1] do 175 | if int chunk.[idx] = SourceNode.NEWLINE_CODE then 176 | generatedLine <- generatedLine + 1 177 | generatedColumn <- 0 178 | // Mappings end at eol 179 | if idx + 1 = chunk.Length then 180 | lastOriginalSource <- None 181 | sourceMappingActive <- false 182 | elif sourceMappingActive then 183 | let _generated: Util.MappingIndex = {line = generatedLine; column = generatedColumn} 184 | let _original: Util.MappingIndex = {line = original.line.Value; column = original.column.Value} 185 | match original.Source,original.Name with 186 | | Some src, Some name -> map.AddMapping(_generated, _original, src,name) 187 | | Some src, None -> map.AddMapping(_generated, _original, src) 188 | | None, Some name -> map.AddMapping(_generated, _original, name=name) 189 | | None, None -> map.AddMapping(_generated, _original) 190 | 191 | else 192 | generatedColumn <- generatedColumn + 1 193 | ) 194 | this.WalkSourceContents(fun (file,content) -> map.SetSourceContent(file,Some content)) 195 | (generatedCode.ToString(), map) 196 | -------------------------------------------------------------------------------- /src/Util.fs: -------------------------------------------------------------------------------- 1 | namespace SourceMapSharp 2 | open System.Collections.Generic 3 | 4 | module Util = 5 | [] 6 | type MappingIndex = {line: int; column: int} 7 | 8 | type Mapping = { 9 | Generated: MappingIndex 10 | Original: MappingIndex option 11 | Source: string option 12 | Name: string option 13 | } 14 | 15 | type SourceGeneratorJSON = 16 | { version: int 17 | sources: seq 18 | names: seq 19 | mappings: string 20 | file: string option 21 | sourcesContent: seq option 22 | sourceRoot: string option } 23 | 24 | #if !FABLE_COMPILER 25 | /// Render the source map being generated to a string. 26 | member this.Serialize() = 27 | System.Text.Json.JsonSerializer.Serialize(this, System.Text.Json.FSharpConverters.Options) 28 | /// Write the source map being generated to a stream. 29 | member this.SerializeAsync stream = 30 | System.Text.Json.JsonSerializer.SerializeAsync(stream, this, System.Text.Json.FSharpConverters.Options) 31 | #endif 32 | 33 | type RawSection = { 34 | offset: MappingIndex 35 | map: SourceGeneratorJSON 36 | } 37 | 38 | type RawIndexMap = { 39 | version: int 40 | file: string option 41 | sourceRoot: string option 42 | skipValidation: bool option 43 | sections: seq 44 | } 45 | 46 | let inline strcmp (s1: string option) (s2:string option) = 47 | if s1.IsSome && s2.IsSome then 48 | if s1.Value = s2.Value then 0 49 | elif s1.Value > s2.Value then 1 50 | else -1 51 | elif s1.IsNone && s2.IsNone then 52 | 0 53 | elif s1.IsNone then 1 54 | elif s2.IsNone then -1 55 | else -1 56 | 57 | let inline compareByGeneratedPositionsInflated (mappingA: Mapping) (mappingB: Mapping) = 58 | let mutable cmp = mappingA.Generated.line - mappingB.Generated.line 59 | if cmp <> 0 then cmp 60 | else 61 | cmp <- mappingA.Generated.column - mappingB.Generated.column 62 | if cmp <> 0 then cmp 63 | else 64 | cmp <- strcmp mappingA.Source mappingB.Source 65 | if cmp <> 0 then cmp 66 | else 67 | match (mappingA.Original,mappingB.Original) with 68 | | (Some mapAOriginal,Some mapBOriginal) -> 69 | cmp <- mapAOriginal.line - mapBOriginal.line 70 | if cmp <> 0 then cmp 71 | else 72 | cmp <- mapAOriginal.column - mapBOriginal.column 73 | if cmp <> 0 then cmp 74 | else strcmp mappingA.Name mappingB.Name 75 | | _ -> strcmp mappingA.Name mappingB.Name 76 | 77 | let [] private dummyFile = "__DUMMY-FILE__.txt" 78 | let private Combine (path1: string, path2: string) = 79 | let path1 = 80 | if path1.Length = 0 then path1 81 | else (path1.TrimEnd [|'\\';'/'|]) + "/" 82 | path1 + (path2.TrimStart [|'\\';'/'|]) 83 | 84 | let private ChangeExtension (path: string, ext: string) = 85 | let i = path.LastIndexOf(".") 86 | if i < 0 then path 87 | else path.Substring(0, i) + ext 88 | 89 | let private GetExtension (path: string) = 90 | let i = path.LastIndexOf(".") 91 | if i < 0 then "" 92 | else path.Substring(i) 93 | 94 | let private normalizePath (path: string) = 95 | path.Replace('\\', '/') 96 | 97 | /// Checks if path starts with "./", ".\" or ".." 98 | let private isRelativePath (path: string) = 99 | let len = path.Length 100 | if len = 0 101 | then false 102 | elif path.[0] = '.' then 103 | if len = 1 104 | then true 105 | // Some folders start with a dot, see #1599 106 | // For simplicity, ignore folders starting with TWO dots 107 | else match path.[1] with 108 | | '/' | '\\' | '.' -> true 109 | | _ -> false 110 | else false 111 | 112 | /// Creates a relative path from one file or folder to another. 113 | let private getRelativeFileOrDirPath fromIsDir fromFullPath toIsDir toFullPath = 114 | // Algorithm adapted from http://stackoverflow.com/a/6244188 115 | let pathDifference (path1: string) (path2: string) = 116 | let mutable c = 0 //index up to which the paths are the same 117 | let mutable d = -1 //index of trailing slash for the portion where the paths are the s 118 | while c < path1.Length && c < path2.Length && path1.[c] = path2.[c] do 119 | if path1.[c] = '/' then d <- c 120 | c <- c + 1 121 | if c = 0 122 | then path2 123 | elif c = path1.Length && c = path2.Length 124 | then "" 125 | else 126 | let mutable builder = "" 127 | while c < path1.Length do 128 | if path1.[c] = '/' then builder <- builder + "../" 129 | c <- c + 1 130 | if builder.Length = 0 && path2.Length - 1 = d 131 | then "./" 132 | else builder + path2.Substring(d + 1) 133 | // Add a dummy file to make it work correctly with dirs 134 | let addDummyFile isDir path = 135 | if isDir 136 | then Combine (path, dummyFile) 137 | else path 138 | // Normalizing shouldn't be necessary at this stage but just in case 139 | let fromFullPath = normalizePath fromFullPath 140 | let toFullPath = normalizePath toFullPath 141 | let fromPath = addDummyFile fromIsDir fromFullPath 142 | let toPath = addDummyFile toIsDir toFullPath 143 | match (pathDifference fromPath toPath).Replace(dummyFile, "") with 144 | | "" -> "." 145 | | path -> path 146 | 147 | let getRelativePath (fromFullPath,toFullPath) = 148 | // This is not 100% reliable, but IO.Directory.Exists doesn't 149 | // work either if the directory doesn't exist (e.g. `outDir`) 150 | let isDir = GetExtension >> System.String.IsNullOrWhiteSpace 151 | // let isDir = IO.Directory.Exists 152 | getRelativeFileOrDirPath (isDir fromFullPath) fromFullPath (isDir toFullPath) toFullPath 153 | 154 | let computeSourceUrl (sourceRoot:string) (sourceUrl:string) (sourceMapUrl:string) = 155 | //TODO 156 | sourceUrl 157 | 158 | 159 | type _MappingComparer() = 160 | interface IComparer with 161 | member _.Compare(a,b) = compareByGeneratedPositionsInflated a b 162 | let sharedMappingComparer = _MappingComparer() 163 | --------------------------------------------------------------------------------