├── .editorconfig
├── .eslintrc.js
├── .gitattributes
├── .github
└── workflows
│ └── nodejs.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── jest.config.js
├── package-lock.json
├── package.json
├── prettier.config.js
├── renovate.json
├── rollup.config.js
├── src
├── build-source-map-tree.ts
├── remapping.ts
├── source-map-tree.ts
├── source-map.ts
└── types.ts
├── test
├── samples
│ ├── null-source
│ │ └── test.ts
│ ├── sourceless-transform
│ │ └── test.ts
│ ├── transpile-concat-hires
│ │ ├── babel.config.js
│ │ ├── build.js
│ │ ├── build.sh
│ │ ├── files
│ │ │ ├── bundle.js
│ │ │ ├── bundle.js.map
│ │ │ ├── main.js
│ │ │ ├── main.js.map
│ │ │ ├── main.mjs
│ │ │ ├── placeholder.js
│ │ │ ├── placeholder.js.map
│ │ │ └── placeholder.mjs
│ │ └── test.ts
│ ├── transpile-concat-lowres
│ │ ├── babel.config.js
│ │ ├── build.js
│ │ ├── build.sh
│ │ ├── files
│ │ │ ├── bundle.js
│ │ │ ├── bundle.js.map
│ │ │ ├── main.js
│ │ │ ├── main.js.map
│ │ │ ├── main.mjs
│ │ │ ├── placeholder.js
│ │ │ ├── placeholder.js.map
│ │ │ └── placeholder.mjs
│ │ └── test.ts
│ ├── transpile-minify
│ │ ├── babel.config.js
│ │ ├── build.sh
│ │ ├── files
│ │ │ ├── helloworld.js
│ │ │ ├── helloworld.js.map
│ │ │ ├── helloworld.min.js
│ │ │ ├── helloworld.min.js.map
│ │ │ └── helloworld.mjs
│ │ └── test.ts
│ └── transpile-rollup
│ │ ├── babel.config.js
│ │ ├── build.sh
│ │ ├── files
│ │ ├── a.js
│ │ ├── a.js.map
│ │ ├── a.mjs
│ │ ├── b.js
│ │ ├── b.js.map
│ │ ├── b.mjs
│ │ ├── bundle.js
│ │ ├── bundle.js.map
│ │ ├── index.js
│ │ ├── index.js.map
│ │ └── index.mjs
│ │ └── test.ts
└── unit
│ ├── build-source-map-tree.ts
│ ├── remapping.ts
│ ├── source-map-tree.ts
│ └── source-map.ts
├── tsconfig.build.json
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | #root = true
2 |
3 | [*]
4 | indent_style = space
5 | end_of_line = lf
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 | max_line_length = 100
10 | indent_size = 2
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: '@typescript-eslint/parser',
4 | plugins: ['@typescript-eslint'],
5 | extends: [
6 | 'eslint:recommended',
7 | 'plugin:@typescript-eslint/recommended',
8 | 'prettier',
9 | ],
10 | rules: {
11 | '@typescript-eslint/consistent-type-imports': 'error',
12 | '@typescript-eslint/no-duplicate-imports': 'error',
13 | '@typescript-eslint/no-explicit-any': 'off',
14 | '@typescript-eslint/no-non-null-assertion': 'off',
15 | '@typescript-eslint/no-unused-vars': [
16 | 'error',
17 | {
18 | argsIgnorePattern: '^_',
19 | },
20 | ],
21 | 'no-constant-condition': 'off',
22 | 'no-unused-labels': 'off',
23 | },
24 | overrides: [
25 | {
26 | files: ['test/**/*.ts'],
27 | rules: {
28 | '@typescript-eslint/no-empty-function': 'off',
29 | '@typescript-eslint/no-explicit-any': 'off',
30 | },
31 | },
32 | ],
33 | };
34 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | /test/samples/** text eol=lf
2 |
--------------------------------------------------------------------------------
/.github/workflows/nodejs.yml:
--------------------------------------------------------------------------------
1 | name: Node CI
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | strategy:
11 | matrix:
12 | node-version: [12.x, 14.x, 16.x]
13 |
14 | steps:
15 | - uses: actions/checkout@v1
16 | - name: Use Node.js ${{ matrix.node-version }}
17 | uses: actions/setup-node@v1
18 | with:
19 | node-version: ${{ matrix.node-version }}
20 | - name: npm install and test
21 | run: |
22 | npm install
23 | npm test
24 | npm run build
25 | env:
26 | CI: true
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | coverage
3 | dist
4 | .rpt2_cache
5 | .vscode
6 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | See https://github.com/ampproject/meta/blob/master/CODE_OF_CONDUCT.md
2 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement. You (or your employer) retain the copyright to your contribution;
10 | this simply gives us permission to use and redistribute your contributions as
11 | part of the project. Head over to to see
12 | your current agreements on file or to sign a new one.
13 |
14 | You generally only need to submit a CLA once, so if you've already submitted one
15 | (even if it was for a different project), you probably don't need to do it
16 | again.
17 |
18 | ## Code reviews
19 |
20 | All submissions, including submissions by project members, require review. We
21 | use GitHub pull requests for this purpose. Consult
22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
23 | information on using pull requests.
24 |
25 | ## Community Guidelines
26 |
27 | This project follows [Google's Open Source Community
28 | Guidelines](https://opensource.google.com/conduct/).
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # @ampproject/remapping
2 |
3 | > Remap sequential sourcemaps through transformations to point at the original source code
4 |
5 | Remapping allows you to take the sourcemaps generated through transforming your code and "remap"
6 | them to the original source locations. Think "my minified code, transformed with babel and bundled
7 | with webpack", all pointing to the correct location in your original source code.
8 |
9 | With remapping, none of your source code transformations need to be aware of the input's sourcemap,
10 | they only need to generate an output sourcemap. This greatly simplifies building custom
11 | transformations (think a find-and-replace).
12 |
13 | ## Installation
14 |
15 | ```sh
16 | npm install @ampproject/remapping
17 | ```
18 |
19 | ## Usage
20 |
21 | ```typescript
22 | function remapping(
23 | map: SourceMap | SourceMap[],
24 | loader: (file: string, ctx: LoaderContext) => (SourceMap | null | undefined),
25 | options?: { excludeContent: boolean, decodedMappings: boolean }
26 | ): SourceMap;
27 |
28 | // LoaderContext gives the loader the importing sourcemap, tree depth, the ability to override the
29 | // "source" location (where child sources are resolved relative to, or the location of original
30 | // source), and the ability to override the "content" of an original source for inclusion in the
31 | // output sourcemap.
32 | type LoaderContext = {
33 | readonly importer: string;
34 | readonly depth: number;
35 | source: string;
36 | content: string | null | undefined;
37 | }
38 | ```
39 |
40 | `remapping` takes the final output sourcemap, and a `loader` function. For every source file pointer
41 | in the sourcemap, the `loader` will be called with the resolved path. If the path itself represents
42 | a transformed file (it has a sourcmap associated with it), then the `loader` should return that
43 | sourcemap. If not, the path will be treated as an original, untransformed source code.
44 |
45 | ```js
46 | // Babel transformed "helloworld.js" into "transformed.js"
47 | const transformedMap = JSON.stringify({
48 | file: 'transformed.js',
49 | // 1st column of 2nd line of output file translates into the 1st source
50 | // file, line 3, column 2
51 | mappings: ';CAEE',
52 | sources: ['helloworld.js'],
53 | version: 3,
54 | });
55 |
56 | // Uglify minified "transformed.js" into "transformed.min.js"
57 | const minifiedTransformedMap = JSON.stringify({
58 | file: 'transformed.min.js',
59 | // 0th column of 1st line of output file translates into the 1st source
60 | // file, line 2, column 1.
61 | mappings: 'AACC',
62 | names: [],
63 | sources: ['transformed.js'],
64 | version: 3,
65 | });
66 |
67 | const remapped = remapping(
68 | minifiedTransformedMap,
69 | (file, ctx) => {
70 |
71 | // The "transformed.js" file is an transformed file.
72 | if (file === 'transformed.js') {
73 | // The root importer is empty.
74 | console.assert(ctx.importer === '');
75 | // The depth in the sourcemap tree we're currently loading.
76 | // The root `minifiedTransformedMap` is depth 0, and its source children are depth 1, etc.
77 | console.assert(ctx.depth === 1);
78 |
79 | return transformedMap;
80 | }
81 |
82 | // Loader will be called to load transformedMap's source file pointers as well.
83 | console.assert(file === 'helloworld.js');
84 | // `transformed.js`'s sourcemap points into `helloworld.js`.
85 | console.assert(ctx.importer === 'transformed.js');
86 | // This is a source child of `transformed`, which is a source child of `minifiedTransformedMap`.
87 | console.assert(ctx.depth === 2);
88 | return null;
89 | }
90 | );
91 |
92 | console.log(remapped);
93 | // {
94 | // file: 'transpiled.min.js',
95 | // mappings: 'AAEE',
96 | // sources: ['helloworld.js'],
97 | // version: 3,
98 | // };
99 | ```
100 |
101 | In this example, `loader` will be called twice:
102 |
103 | 1. `"transformed.js"`, the first source file pointer in the `minifiedTransformedMap`. We return the
104 | associated sourcemap for it (its a transformed file, after all) so that sourcemap locations can
105 | be traced through it into the source files it represents.
106 | 2. `"helloworld.js"`, our original, unmodified source code. This file does not have a sourcemap, so
107 | we return `null`.
108 |
109 | The `remapped` sourcemap now points from `transformed.min.js` into locations in `helloworld.js`. If
110 | you were to read the `mappings`, it says "0th column of the first line output line points to the 1st
111 | column of the 2nd line of the file `helloworld.js`".
112 |
113 | ### Multiple transformations of a file
114 |
115 | As a convenience, if you have multiple single-source transformations of a file, you may pass an
116 | array of sourcemap files in the order of most-recent transformation sourcemap first. Note that this
117 | changes the `importer` and `depth` of each call to our loader. So our above example could have been
118 | written as:
119 |
120 | ```js
121 | const remapped = remapping(
122 | [minifiedTransformedMap, transformedMap],
123 | () => null
124 | );
125 |
126 | console.log(remapped);
127 | // {
128 | // file: 'transpiled.min.js',
129 | // mappings: 'AAEE',
130 | // sources: ['helloworld.js'],
131 | // version: 3,
132 | // };
133 | ```
134 |
135 | ### Advanced control of the loading graph
136 |
137 | #### `source`
138 |
139 | The `source` property can overridden to any value to change the location of the current load. Eg,
140 | for an original source file, it allows us to change the location to the original source regardless
141 | of what the sourcemap source entry says. And for transformed files, it allows us to change the
142 | relative resolving location for child sources of the loaded sourcemap.
143 |
144 | ```js
145 | const remapped = remapping(
146 | minifiedTransformedMap,
147 | (file, ctx) => {
148 |
149 | if (file === 'transformed.js') {
150 | // We pretend the transformed.js file actually exists in the 'src/' directory. When the nested
151 | // source files are loaded, they will now be relative to `src/`.
152 | ctx.source = 'src/transformed.js';
153 | return transformedMap;
154 | }
155 |
156 | console.assert(file === 'src/helloworld.js');
157 | // We could futher change the source of this original file, eg, to be inside a nested directory
158 | // itself. This will be reflected in the remapped sourcemap.
159 | ctx.source = 'src/nested/transformed.js';
160 | return null;
161 | }
162 | );
163 |
164 | console.log(remapped);
165 | // {
166 | // …,
167 | // sources: ['src/nested/helloworld.js'],
168 | // };
169 | ```
170 |
171 |
172 | #### `content`
173 |
174 | The `content` property can be overridden when we encounter an original source file. Eg, this allows
175 | you to manually provide the source content of the original file regardless of whether the
176 | `sourcesContent` field is present in the parent sourcemap. It can also be set to `null` to remove
177 | the source content.
178 |
179 | ```js
180 | const remapped = remapping(
181 | minifiedTransformedMap,
182 | (file, ctx) => {
183 |
184 | if (file === 'transformed.js') {
185 | // transformedMap does not include a `sourcesContent` field, so usually the remapped sourcemap
186 | // would not include any `sourcesContent` values.
187 | return transformedMap;
188 | }
189 |
190 | console.assert(file === 'helloworld.js');
191 | // We can read the file to provide the source content.
192 | ctx.content = fs.readFileSync(file, 'utf8');
193 | return null;
194 | }
195 | );
196 |
197 | console.log(remapped);
198 | // {
199 | // …,
200 | // sourcesContent: [
201 | // 'console.log("Hello world!")',
202 | // ],
203 | // };
204 | ```
205 |
206 | ### Options
207 |
208 | #### excludeContent
209 |
210 | By default, `excludeContent` is `false`. Passing `{ excludeContent: true }` will exclude the
211 | `sourcesContent` field from the returned sourcemap. This is mainly useful when you want to reduce
212 | the size out the sourcemap.
213 |
214 | #### decodedMappings
215 |
216 | By default, `decodedMappings` is `false`. Passing `{ decodedMappings: true }` will leave the
217 | `mappings` field in a [decoded state](https://github.com/rich-harris/sourcemap-codec) instead of
218 | encoding into a VLQ string.
219 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | transform: {
3 | '.ts': 'ts-jest',
4 | },
5 | testMatch: ['**/test/**/*.ts'],
6 | moduleFileExtensions: ['ts', 'js'],
7 | coveragePathIgnorePatterns: ['/node_modules/', '/test/'],
8 | coverageThreshold: {
9 | global: {
10 | branches: 90,
11 | functions: 95,
12 | lines: 95,
13 | statements: 95,
14 | },
15 | },
16 | collectCoverageFrom: ['src/**/*.ts'],
17 | };
18 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@ampproject/remapping",
3 | "version": "2.3.0",
4 | "description": "Remap sequential sourcemaps through transformations to point at the original source code",
5 | "keywords": [
6 | "source",
7 | "map",
8 | "remap"
9 | ],
10 | "main": "dist/remapping.umd.js",
11 | "module": "dist/remapping.mjs",
12 | "types": "dist/types/remapping.d.ts",
13 | "exports": {
14 | ".": [
15 | {
16 | "types": "./dist/types/remapping.d.ts",
17 | "browser": "./dist/remapping.umd.js",
18 | "require": "./dist/remapping.umd.js",
19 | "import": "./dist/remapping.mjs"
20 | },
21 | "./dist/remapping.umd.js"
22 | ],
23 | "./package.json": "./package.json"
24 | },
25 | "files": [
26 | "dist"
27 | ],
28 | "author": "Justin Ridgewell ",
29 | "repository": {
30 | "type": "git",
31 | "url": "git+https://github.com/ampproject/remapping.git"
32 | },
33 | "license": "Apache-2.0",
34 | "engines": {
35 | "node": ">=6.0.0"
36 | },
37 | "scripts": {
38 | "build": "run-s -n build:*",
39 | "build:rollup": "rollup -c rollup.config.js",
40 | "build:ts": "tsc --project tsconfig.build.json",
41 | "lint": "run-s -n lint:*",
42 | "lint:prettier": "npm run test:lint:prettier -- --write",
43 | "lint:ts": "npm run test:lint:ts -- --fix",
44 | "prebuild": "rm -rf dist",
45 | "prepublishOnly": "npm run preversion",
46 | "preversion": "run-s test build",
47 | "test": "run-s -n test:lint test:only",
48 | "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
49 | "test:lint": "run-s -n test:lint:*",
50 | "test:lint:prettier": "prettier --check '{src,test}/**/*.ts'",
51 | "test:lint:ts": "eslint '{src,test}/**/*.ts'",
52 | "test:only": "jest --coverage",
53 | "test:watch": "jest --coverage --watch"
54 | },
55 | "devDependencies": {
56 | "@rollup/plugin-typescript": "8.3.2",
57 | "@types/jest": "27.4.1",
58 | "@typescript-eslint/eslint-plugin": "5.20.0",
59 | "@typescript-eslint/parser": "5.20.0",
60 | "eslint": "8.14.0",
61 | "eslint-config-prettier": "8.5.0",
62 | "jest": "27.5.1",
63 | "jest-config": "27.5.1",
64 | "npm-run-all": "4.1.5",
65 | "prettier": "2.6.2",
66 | "rollup": "2.70.2",
67 | "ts-jest": "27.1.4",
68 | "tslib": "2.4.0",
69 | "typescript": "4.6.3"
70 | },
71 | "dependencies": {
72 | "@jridgewell/gen-mapping": "^0.3.5",
73 | "@jridgewell/trace-mapping": "^0.3.24"
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | endOfLine: 'lf',
3 | printWidth: 100,
4 | singleQuote: true,
5 | trailingComma: 'es5',
6 | };
7 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "config:base"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import typescript from '@rollup/plugin-typescript';
2 |
3 | function configure(esm) {
4 | return {
5 | input: 'src/remapping.ts',
6 | output: esm
7 | ? { format: 'es', dir: 'dist', entryFileNames: '[name].mjs', sourcemap: true }
8 | : {
9 | format: 'umd',
10 | name: 'remapping',
11 | dir: 'dist',
12 | entryFileNames: '[name].umd.js',
13 | sourcemap: true,
14 | globals: {
15 | '@jridgewell/gen-mapping': 'genMapping',
16 | '@jridgewell/trace-mapping': 'traceMapping',
17 | },
18 | },
19 | plugins: [typescript({ tsconfig: './tsconfig.build.json' })],
20 | watch: {
21 | include: 'src/**',
22 | },
23 | };
24 | }
25 |
26 | export default [configure(false), configure(true)];
27 |
--------------------------------------------------------------------------------
/src/build-source-map-tree.ts:
--------------------------------------------------------------------------------
1 | import { TraceMap } from '@jridgewell/trace-mapping';
2 |
3 | import { OriginalSource, MapSource } from './source-map-tree';
4 |
5 | import type { Sources, MapSource as MapSourceType } from './source-map-tree';
6 | import type { SourceMapInput, SourceMapLoader, LoaderContext } from './types';
7 |
8 | function asArray(value: T | T[]): T[] {
9 | if (Array.isArray(value)) return value;
10 | return [value];
11 | }
12 |
13 | /**
14 | * Recursively builds a tree structure out of sourcemap files, with each node
15 | * being either an `OriginalSource` "leaf" or a `SourceMapTree` composed of
16 | * `OriginalSource`s and `SourceMapTree`s.
17 | *
18 | * Every sourcemap is composed of a collection of source files and mappings
19 | * into locations of those source files. When we generate a `SourceMapTree` for
20 | * the sourcemap, we attempt to load each source file's own sourcemap. If it
21 | * does not have an associated sourcemap, it is considered an original,
22 | * unmodified source file.
23 | */
24 | export default function buildSourceMapTree(
25 | input: SourceMapInput | SourceMapInput[],
26 | loader: SourceMapLoader
27 | ): MapSourceType {
28 | const maps = asArray(input).map((m) => new TraceMap(m, ''));
29 | const map = maps.pop()!;
30 |
31 | for (let i = 0; i < maps.length; i++) {
32 | if (maps[i].sources.length > 1) {
33 | throw new Error(
34 | `Transformation map ${i} must have exactly one source file.\n` +
35 | 'Did you specify these with the most recent transformation maps first?'
36 | );
37 | }
38 | }
39 |
40 | let tree = build(map, loader, '', 0);
41 | for (let i = maps.length - 1; i >= 0; i--) {
42 | tree = MapSource(maps[i], [tree]);
43 | }
44 | return tree;
45 | }
46 |
47 | function build(
48 | map: TraceMap,
49 | loader: SourceMapLoader,
50 | importer: string,
51 | importerDepth: number
52 | ): MapSourceType {
53 | const { resolvedSources, sourcesContent, ignoreList } = map;
54 |
55 | const depth = importerDepth + 1;
56 | const children = resolvedSources.map((sourceFile: string | null, i: number): Sources => {
57 | // The loading context gives the loader more information about why this file is being loaded
58 | // (eg, from which importer). It also allows the loader to override the location of the loaded
59 | // sourcemap/original source, or to override the content in the sourcesContent field if it's
60 | // an unmodified source file.
61 | const ctx: LoaderContext = {
62 | importer,
63 | depth,
64 | source: sourceFile || '',
65 | content: undefined,
66 | ignore: undefined,
67 | };
68 |
69 | // Use the provided loader callback to retrieve the file's sourcemap.
70 | // TODO: We should eventually support async loading of sourcemap files.
71 | const sourceMap = loader(ctx.source, ctx);
72 |
73 | const { source, content, ignore } = ctx;
74 |
75 | // If there is a sourcemap, then we need to recurse into it to load its source files.
76 | if (sourceMap) return build(new TraceMap(sourceMap, source), loader, source, depth);
77 |
78 | // Else, it's an unmodified source file.
79 | // The contents of this unmodified source file can be overridden via the loader context,
80 | // allowing it to be explicitly null or a string. If it remains undefined, we fall back to
81 | // the importing sourcemap's `sourcesContent` field.
82 | const sourceContent =
83 | content !== undefined ? content : sourcesContent ? sourcesContent[i] : null;
84 | const ignored = ignore !== undefined ? ignore : ignoreList ? ignoreList.includes(i) : false;
85 | return OriginalSource(source, sourceContent, ignored);
86 | });
87 |
88 | return MapSource(map, children);
89 | }
90 |
--------------------------------------------------------------------------------
/src/remapping.ts:
--------------------------------------------------------------------------------
1 | import buildSourceMapTree from './build-source-map-tree';
2 | import { traceMappings } from './source-map-tree';
3 | import SourceMap from './source-map';
4 |
5 | import type { SourceMapInput, SourceMapLoader, Options } from './types';
6 | export type {
7 | SourceMapSegment,
8 | EncodedSourceMap,
9 | EncodedSourceMap as RawSourceMap,
10 | DecodedSourceMap,
11 | SourceMapInput,
12 | SourceMapLoader,
13 | LoaderContext,
14 | Options,
15 | } from './types';
16 | export type { SourceMap };
17 |
18 | /**
19 | * Traces through all the mappings in the root sourcemap, through the sources
20 | * (and their sourcemaps), all the way back to the original source location.
21 | *
22 | * `loader` will be called every time we encounter a source file. If it returns
23 | * a sourcemap, we will recurse into that sourcemap to continue the trace. If
24 | * it returns a falsey value, that source file is treated as an original,
25 | * unmodified source file.
26 | *
27 | * Pass `excludeContent` to exclude any self-containing source file content
28 | * from the output sourcemap.
29 | *
30 | * Pass `decodedMappings` to receive a SourceMap with decoded (instead of
31 | * VLQ encoded) mappings.
32 | */
33 | export default function remapping(
34 | input: SourceMapInput | SourceMapInput[],
35 | loader: SourceMapLoader,
36 | options?: boolean | Options
37 | ): SourceMap {
38 | const opts =
39 | typeof options === 'object' ? options : { excludeContent: !!options, decodedMappings: false };
40 | const tree = buildSourceMapTree(input, loader);
41 | return new SourceMap(traceMappings(tree), opts);
42 | }
43 |
--------------------------------------------------------------------------------
/src/source-map-tree.ts:
--------------------------------------------------------------------------------
1 | import { GenMapping, maybeAddSegment, setIgnore, setSourceContent } from '@jridgewell/gen-mapping';
2 | import { traceSegment, decodedMappings } from '@jridgewell/trace-mapping';
3 |
4 | import type { TraceMap } from '@jridgewell/trace-mapping';
5 |
6 | export type SourceMapSegmentObject = {
7 | column: number;
8 | line: number;
9 | name: string;
10 | source: string;
11 | content: string | null;
12 | ignore: boolean;
13 | };
14 |
15 | export type OriginalSource = {
16 | map: null;
17 | sources: Sources[];
18 | source: string;
19 | content: string | null;
20 | ignore: boolean;
21 | };
22 |
23 | export type MapSource = {
24 | map: TraceMap;
25 | sources: Sources[];
26 | source: string;
27 | content: null;
28 | ignore: false;
29 | };
30 |
31 | export type Sources = OriginalSource | MapSource;
32 |
33 | const SOURCELESS_MAPPING = /* #__PURE__ */ SegmentObject('', -1, -1, '', null, false);
34 | const EMPTY_SOURCES: Sources[] = [];
35 |
36 | function SegmentObject(
37 | source: string,
38 | line: number,
39 | column: number,
40 | name: string,
41 | content: string | null,
42 | ignore: boolean
43 | ): SourceMapSegmentObject {
44 | return { source, line, column, name, content, ignore };
45 | }
46 |
47 | function Source(
48 | map: TraceMap,
49 | sources: Sources[],
50 | source: '',
51 | content: null,
52 | ignore: false
53 | ): MapSource;
54 | function Source(
55 | map: null,
56 | sources: Sources[],
57 | source: string,
58 | content: string | null,
59 | ignore: boolean
60 | ): OriginalSource;
61 | function Source(
62 | map: TraceMap | null,
63 | sources: Sources[],
64 | source: string | '',
65 | content: string | null,
66 | ignore: boolean
67 | ): Sources {
68 | return {
69 | map,
70 | sources,
71 | source,
72 | content,
73 | ignore,
74 | } as any;
75 | }
76 |
77 | /**
78 | * MapSource represents a single sourcemap, with the ability to trace mappings into its child nodes
79 | * (which may themselves be SourceMapTrees).
80 | */
81 | export function MapSource(map: TraceMap, sources: Sources[]): MapSource {
82 | return Source(map, sources, '', null, false);
83 | }
84 |
85 | /**
86 | * A "leaf" node in the sourcemap tree, representing an original, unmodified source file. Recursive
87 | * segment tracing ends at the `OriginalSource`.
88 | */
89 | export function OriginalSource(
90 | source: string,
91 | content: string | null,
92 | ignore: boolean
93 | ): OriginalSource {
94 | return Source(null, EMPTY_SOURCES, source, content, ignore);
95 | }
96 |
97 | /**
98 | * traceMappings is only called on the root level SourceMapTree, and begins the process of
99 | * resolving each mapping in terms of the original source files.
100 | */
101 | export function traceMappings(tree: MapSource): GenMapping {
102 | // TODO: Eventually support sourceRoot, which has to be removed because the sources are already
103 | // fully resolved. We'll need to make sources relative to the sourceRoot before adding them.
104 | const gen = new GenMapping({ file: tree.map.file });
105 | const { sources: rootSources, map } = tree;
106 | const rootNames = map.names;
107 | const rootMappings = decodedMappings(map);
108 |
109 | for (let i = 0; i < rootMappings.length; i++) {
110 | const segments = rootMappings[i];
111 |
112 | for (let j = 0; j < segments.length; j++) {
113 | const segment = segments[j];
114 | const genCol = segment[0];
115 | let traced: SourceMapSegmentObject | null = SOURCELESS_MAPPING;
116 |
117 | // 1-length segments only move the current generated column, there's no source information
118 | // to gather from it.
119 | if (segment.length !== 1) {
120 | const source = rootSources[segment[1]];
121 | traced = originalPositionFor(
122 | source,
123 | segment[2],
124 | segment[3],
125 | segment.length === 5 ? rootNames[segment[4]] : ''
126 | );
127 |
128 | // If the trace is invalid, then the trace ran into a sourcemap that doesn't contain a
129 | // respective segment into an original source.
130 | if (traced == null) continue;
131 | }
132 |
133 | const { column, line, name, content, source, ignore } = traced;
134 |
135 | maybeAddSegment(gen, i, genCol, source, line, column, name);
136 | if (source && content != null) setSourceContent(gen, source, content);
137 | if (ignore) setIgnore(gen, source, true);
138 | }
139 | }
140 |
141 | return gen;
142 | }
143 |
144 | /**
145 | * originalPositionFor is only called on children SourceMapTrees. It recurses down into its own
146 | * child SourceMapTrees, until we find the original source map.
147 | */
148 | export function originalPositionFor(
149 | source: Sources,
150 | line: number,
151 | column: number,
152 | name: string
153 | ): SourceMapSegmentObject | null {
154 | if (!source.map) {
155 | return SegmentObject(source.source, line, column, name, source.content, source.ignore);
156 | }
157 |
158 | const segment = traceSegment(source.map, line, column);
159 |
160 | // If we couldn't find a segment, then this doesn't exist in the sourcemap.
161 | if (segment == null) return null;
162 | // 1-length segments only move the current generated column, there's no source information
163 | // to gather from it.
164 | if (segment.length === 1) return SOURCELESS_MAPPING;
165 |
166 | return originalPositionFor(
167 | source.sources[segment[1]],
168 | segment[2],
169 | segment[3],
170 | segment.length === 5 ? source.map.names[segment[4]] : name
171 | );
172 | }
173 |
--------------------------------------------------------------------------------
/src/source-map.ts:
--------------------------------------------------------------------------------
1 | import { toDecodedMap, toEncodedMap } from '@jridgewell/gen-mapping';
2 |
3 | import type { GenMapping } from '@jridgewell/gen-mapping';
4 | import type { DecodedSourceMap, EncodedSourceMap, Options } from './types';
5 |
6 | /**
7 | * A SourceMap v3 compatible sourcemap, which only includes fields that were
8 | * provided to it.
9 | */
10 | export default class SourceMap {
11 | declare file?: string | null;
12 | declare mappings: EncodedSourceMap['mappings'] | DecodedSourceMap['mappings'];
13 | declare sourceRoot?: string;
14 | declare names: string[];
15 | declare sources: (string | null)[];
16 | declare sourcesContent?: (string | null)[];
17 | declare version: 3;
18 | declare ignoreList: number[] | undefined;
19 |
20 | constructor(map: GenMapping, options: Options) {
21 | const out = options.decodedMappings ? toDecodedMap(map) : toEncodedMap(map);
22 | this.version = out.version; // SourceMap spec says this should be first.
23 | this.file = out.file;
24 | this.mappings = out.mappings as SourceMap['mappings'];
25 | this.names = out.names as SourceMap['names'];
26 | this.ignoreList = out.ignoreList as SourceMap['ignoreList'];
27 | this.sourceRoot = out.sourceRoot;
28 |
29 | this.sources = out.sources as SourceMap['sources'];
30 | if (!options.excludeContent) {
31 | this.sourcesContent = out.sourcesContent as SourceMap['sourcesContent'];
32 | }
33 | }
34 |
35 | toString(): string {
36 | return JSON.stringify(this);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | import type { SourceMapInput } from '@jridgewell/trace-mapping';
2 |
3 | export type {
4 | SourceMapSegment,
5 | DecodedSourceMap,
6 | EncodedSourceMap,
7 | } from '@jridgewell/trace-mapping';
8 |
9 | export type { SourceMapInput };
10 |
11 | export type LoaderContext = {
12 | readonly importer: string;
13 | readonly depth: number;
14 | source: string;
15 | content: string | null | undefined;
16 | ignore: boolean | undefined;
17 | };
18 |
19 | export type SourceMapLoader = (
20 | file: string,
21 | ctx: LoaderContext
22 | ) => SourceMapInput | null | undefined | void;
23 |
24 | export type Options = {
25 | excludeContent?: boolean;
26 | decodedMappings?: boolean;
27 | };
28 |
--------------------------------------------------------------------------------
/test/samples/null-source/test.ts:
--------------------------------------------------------------------------------
1 | import type { RawSourceMap } from 'source-map';
2 | import { SourceMapConsumer } from 'source-map';
3 | import remapping from '../../../src/remapping';
4 |
5 | describe('null-source segement', () => {
6 | const original: any = {
7 | version: '3',
8 | sources: ['source.ts'],
9 | names: [],
10 | mappings: 'AAAA,qC,aACA',
11 | sourcesContent: ["function say(msg) {console.log(msg)};say('hello');\nprocess.exit(1);"],
12 | };
13 | const minified: any = {
14 | version: '3',
15 | sources: ['source.js'],
16 | names: ['say', 'msg', 'console', 'log', 'process', 'exit'],
17 | mappings: 'AAAA,SAASA,IAAIC,GAAMC,QAAQC,IAAIF,GAAMD,IAAI,SAASI,QAAQC,KAAK',
18 | };
19 |
20 | test('minified code keeps null-source segment', () => {
21 | const remapped = remapping([minified, original], () => null);
22 | const consumer = new SourceMapConsumer(remapped as unknown as RawSourceMap);
23 |
24 | const console = consumer.originalPositionFor({
25 | column: 20,
26 | line: 1,
27 | });
28 | expect(console).toMatchObject({
29 | column: 0,
30 | line: 1,
31 | source: 'source.ts',
32 | });
33 |
34 | const say = consumer.originalPositionFor({
35 | column: 38,
36 | line: 1,
37 | });
38 | expect(say).toMatchObject({
39 | column: null,
40 | line: null,
41 | source: null,
42 | });
43 |
44 | const exit = consumer.originalPositionFor({
45 | column: 53,
46 | line: 1,
47 | });
48 | expect(exit).toMatchObject({
49 | column: 0,
50 | line: 2,
51 | source: 'source.ts',
52 | });
53 | });
54 |
55 | test('null-source', () => {
56 | const remapped = remapping(original, () => null);
57 | const consumer = new SourceMapConsumer(remapped as unknown as RawSourceMap);
58 |
59 | const console = consumer.originalPositionFor({
60 | column: 20,
61 | line: 1,
62 | });
63 | expect(console).toMatchObject({
64 | column: 0,
65 | line: 1,
66 | source: 'source.ts',
67 | });
68 |
69 | const say = consumer.originalPositionFor({
70 | column: 38,
71 | line: 1,
72 | });
73 | expect(say).toMatchObject({
74 | column: null,
75 | line: null,
76 | source: null,
77 | });
78 |
79 | const exit = consumer.originalPositionFor({
80 | column: 53,
81 | line: 1,
82 | });
83 | expect(exit).toMatchObject({
84 | column: 0,
85 | line: 2,
86 | source: 'source.ts',
87 | });
88 | });
89 | });
90 |
--------------------------------------------------------------------------------
/test/samples/sourceless-transform/test.ts:
--------------------------------------------------------------------------------
1 | import remapping from '../../../src/remapping';
2 |
3 | describe('source-less transform', () => {
4 | const original: any = {
5 | version: '3',
6 | sources: ['source.ts'],
7 | names: [],
8 | mappings: 'AAAA',
9 | sourcesContent: ['// hello'],
10 | };
11 | const minified: any = {
12 | version: '3',
13 | sources: [],
14 | names: [],
15 | mappings: '',
16 | };
17 |
18 | test('remapping with loader generates empty sourcemap', () => {
19 | const loader = jest.fn(() => null);
20 | loader.mockReturnValueOnce(original);
21 | const remapped = remapping(minified, loader);
22 |
23 | expect(loader).not.toHaveBeenCalled();
24 | expect(remapped.sources).toHaveLength(0);
25 | expect(remapped.mappings).toBe('');
26 | });
27 |
28 | test('remapping with array shorthand generates empty sourcemap', () => {
29 | const loader = jest.fn(() => null);
30 | const remapped = remapping([minified, original], loader);
31 |
32 | expect(loader).toHaveBeenCalledTimes(1);
33 | expect(loader).toHaveBeenCalledWith('source.ts', expect.anything());
34 | expect(remapped.sources).toHaveLength(0);
35 | expect(remapped.mappings).toBe('');
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-hires/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(false);
3 |
4 | return {
5 | presets: [['@babel/preset-env', { modules: false }]],
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-hires/build.js:
--------------------------------------------------------------------------------
1 | const MagicString = require('magic-string');
2 | const { readFileSync, writeFileSync } = require('fs');
3 |
4 | function load(filename) {
5 | const contents = readFileSync(`${__dirname}/files/${filename}`, 'utf8');
6 | return new MagicString(contents, { filename });
7 | }
8 | function save(filename, contents) {
9 | writeFileSync(`${__dirname}/files/${filename}`, contents);
10 | }
11 |
12 | const main = load('main.js');
13 | const placeholder = load('placeholder.js');
14 |
15 | const search = '/* PLACEHOLDER */';
16 | const index = main.original.indexOf(search);
17 |
18 | const before = main.snip(0, index);
19 | const after = main.snip(index + search.length, main.length());
20 |
21 | const bundle = new MagicString.Bundle();
22 | bundle.addSource(before);
23 | bundle.addSource(placeholder);
24 | bundle.addSource(after);
25 |
26 | save('bundle.js', bundle.toString());
27 | save('bundle.js.map', bundle.generateMap({
28 | hires: true,
29 | includeContent: true,
30 | }).toString());
31 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-hires/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | DIR="$(dirname $0)"
3 | NODE_BIN=`npm bin`
4 | NODE_MODULES=`npm prefix`/node_modules
5 |
6 | rm "$DIR"/files/*.js*
7 |
8 | if [ ! -f "$NODE_BIN/babel" ]; then
9 | npm install --no-save @babel/cli @babel/preset-env
10 | fi
11 | "$NODE_BIN/babel" "$DIR/files" --config-file "./$DIR/babel.config.js" --source-maps -d "$DIR/files"
12 |
13 | if [ ! -d "$NODE_MODULES/magic-string" ]; then
14 | npm install --no-save magic-string
15 | fi
16 |
17 | node "$DIR/build.js"
18 | npx prettier "$DIR/files/*.map" --parser json --write
19 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-hires/files/bundle.js:
--------------------------------------------------------------------------------
1 | var foo = function foo() {
2 | return 'foo';
3 | };
4 |
5 | var bar = function bar() {
6 | return 'bar';
7 | };
8 | //# sourceMappingURL=placeholder.js.map
9 |
10 |
11 |
12 | var baz = function baz() {
13 | return 'baz';
14 | };
15 | //# sourceMappingURL=main.js.map
16 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-hires/files/bundle.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "file": null,
4 | "sources": ["main.js", "placeholder.js"],
5 | "sourcesContent": [
6 | "/**\n * Copyright 2019 The AMP HTML Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nvar foo = function foo() {\n return 'foo';\n};\n/* PLACEHOLDER */\n\n\nvar baz = function baz() {\n return 'baz';\n};\n//# sourceMappingURL=main.js.map",
7 | "/**\n * Copyright 2019 The AMP HTML Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nvar bar = function bar() {\n return 'bar';\n};\n//# sourceMappingURL=placeholder.js.map"
8 | ],
9 | "names": [],
10 | "mappings": "AAAA,CAAC,CAAC,CAAC;AACH,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3E,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,CAAC,CAAC,CAAC;AACH,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACf,CAAC,CAAC;AACF;AClBA,CAAC,CAAC,CAAC;AACH,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3E,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,CAAC,CAAC,CAAC;AACH,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACf,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;uCAAC,vCDAtB;AACjB;AACA;AACA,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACf,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC"
11 | }
12 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-hires/files/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | var foo = function foo() {
17 | return 'foo';
18 | };
19 | /* PLACEHOLDER */
20 |
21 |
22 | var baz = function baz() {
23 | return 'baz';
24 | };
25 | //# sourceMappingURL=main.js.map
--------------------------------------------------------------------------------
/test/samples/transpile-concat-hires/files/main.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "sources": ["main.mjs"],
4 | "names": ["foo", "baz"],
5 | "mappings": "AAAA;;;;;;;;;;;;;;;AAgBA,IAAMA,GAAG,GAAG,SAANA,GAAM;AAAA,SAAM,KAAN;AAAA,CAAZ;AAEA;;;AAEA,IAAMC,GAAG,GAAG,SAANA,GAAM;AAAA,SAAM,KAAN;AAAA,CAAZ",
6 | "sourcesContent": [
7 | "/**\n * Copyright 2019 The AMP HTML Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst foo = () => 'foo';\n\n/* PLACEHOLDER */\n\nconst baz = () => 'baz';\n"
8 | ],
9 | "file": "main.js"
10 | }
11 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-hires/files/main.mjs:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | const foo = () => 'foo';
18 |
19 | /* PLACEHOLDER */
20 |
21 | const baz = () => 'baz';
22 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-hires/files/placeholder.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | var bar = function bar() {
17 | return 'bar';
18 | };
19 | //# sourceMappingURL=placeholder.js.map
--------------------------------------------------------------------------------
/test/samples/transpile-concat-hires/files/placeholder.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "sources": ["placeholder.mjs"],
4 | "names": ["bar"],
5 | "mappings": "AAAA;;;;;;;;;;;;;;;AAgBA,IAAMA,GAAG,GAAG,SAANA,GAAM;AAAA,SAAM,KAAN;AAAA,CAAZ",
6 | "sourcesContent": [
7 | "/**\n * Copyright 2019 The AMP HTML Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst bar = () => 'bar';\n"
8 | ],
9 | "file": "placeholder.js"
10 | }
11 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-hires/files/placeholder.mjs:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | const bar = () => 'bar';
18 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-hires/test.ts:
--------------------------------------------------------------------------------
1 | import { readFileSync } from 'fs';
2 | import type { RawSourceMap } from 'source-map';
3 | import { SourceMapConsumer } from 'source-map';
4 | import remapping from '../../../src/remapping';
5 |
6 | function read(filename: string): string {
7 | return readFileSync(`${__dirname}/files/${filename}`, 'utf8');
8 | }
9 |
10 | describe('transpile then concatenate', () => {
11 | test('concated sections point to source files', () => {
12 | const map = read('bundle.js.map');
13 | const remapped = remapping(map, (file) => {
14 | return file.endsWith('.mjs') ? null : read(`${file}.map`);
15 | });
16 |
17 | const consumer = new SourceMapConsumer(remapped as unknown as RawSourceMap);
18 | // the foo in bundle.js
19 | for (let j = 10; j <= 12; j++) {
20 | const foo = consumer.originalPositionFor({
21 | column: j,
22 | line: 17,
23 | });
24 | expect(foo).toMatchObject({
25 | column: 18,
26 | line: 17,
27 | source: 'main.mjs',
28 | });
29 | }
30 |
31 | // the bar in bundle.js
32 | for (let j = 10; j <= 12; j++) {
33 | const bar = consumer.originalPositionFor({
34 | column: j,
35 | line: 36,
36 | });
37 | expect(bar).toMatchObject({
38 | column: 18,
39 | line: 17,
40 | source: 'placeholder.mjs',
41 | });
42 | }
43 |
44 | //the baz in bundle.js
45 | for (let j = 10; j <= 12; j++) {
46 | const baz = consumer.originalPositionFor({
47 | column: j,
48 | line: 43,
49 | });
50 | expect(baz).toMatchObject({
51 | column: 18,
52 | line: 21,
53 | source: 'main.mjs',
54 | });
55 | }
56 | });
57 |
58 | test('inherits sourcesContent of original sources', () => {
59 | const map = read('bundle.js.map');
60 | const remapped = remapping(map, (file) => {
61 | return file.endsWith('.mjs') ? null : read(`${file}.map`);
62 | });
63 |
64 | expect(remapped.sourcesContent).toEqual([read('main.mjs'), read('placeholder.mjs')]);
65 | });
66 | });
67 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-lowres/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(false);
3 |
4 | return {
5 | presets: [['@babel/preset-env', { modules: false }]],
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-lowres/build.js:
--------------------------------------------------------------------------------
1 | const MagicString = require('magic-string');
2 | const parser = require('@babel/parser');
3 | const { default: traverse } = require('@babel/traverse');
4 | const { readFileSync, writeFileSync } = require('fs');
5 |
6 | function load(filename) {
7 | const contents = readFileSync(`${__dirname}/files/${filename}`, 'utf8');
8 | const s = new MagicString(contents, { filename });
9 | const ast = parser.parse(contents);
10 | traverse.cheap(ast, (node) => {
11 | s.addSourcemapLocation(node.start);
12 | s.addSourcemapLocation(node.end);
13 | });
14 | return s;
15 | }
16 | function save(filename, contents) {
17 | writeFileSync(`${__dirname}/files/${filename}`, contents);
18 | }
19 |
20 | const main = load('main.js');
21 | const placeholder = load('placeholder.js');
22 |
23 | const search = '/* PLACEHOLDER */';
24 | const index = main.original.indexOf(search);
25 |
26 | const before = main.snip(0, index);
27 | const after = main.snip(index + search.length, main.length());
28 |
29 | const bundle = new MagicString.Bundle();
30 | bundle.addSource(before);
31 | bundle.addSource(placeholder);
32 | bundle.addSource(after);
33 |
34 | save('bundle.js', bundle.toString());
35 | save('bundle.js.map', bundle.generateMap({
36 | hires: false,
37 | includeContent: true,
38 | }).toString());
39 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-lowres/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | DIR="$(dirname $0)"
3 | NODE_BIN=`npm bin`
4 | NODE_MODULES=`npm prefix`/node_modules
5 |
6 | rm "$DIR"/files/*.js*
7 |
8 | if [ ! -f "$NODE_BIN/babel" ]; then
9 | npm install --no-save @babel/cli @babel/preset-env
10 | fi
11 | "$NODE_BIN/babel" "$DIR/files" --config-file "./$DIR/babel.config.js" --source-maps -d "$DIR/files"
12 |
13 | if [ ! -d "$NODE_MODULES/magic-string" ]; then
14 | npm install --no-save magic-string
15 | fi
16 |
17 | node "$DIR/build.js"
18 | npx prettier "$DIR/files/*.map" --parser json --write
19 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-lowres/files/bundle.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | var foo = function foo() {
17 | return 'foo';
18 | };
19 |
20 | /**
21 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
22 | *
23 | * Licensed under the Apache License, Version 2.0 (the "License");
24 | * you may not use this file except in compliance with the License.
25 | * You may obtain a copy of the License at
26 | *
27 | * http://www.apache.org/licenses/LICENSE-2.0
28 | *
29 | * Unless required by applicable law or agreed to in writing, software
30 | * distributed under the License is distributed on an "AS IS" BASIS,
31 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32 | * See the License for the specific language governing permissions and
33 | * limitations under the License.
34 | */
35 | var bar = function bar() {
36 | return 'bar';
37 | };
38 | //# sourceMappingURL=placeholder.js.map
39 |
40 |
41 |
42 | var baz = function baz() {
43 | return 'baz';
44 | };
45 | //# sourceMappingURL=main.js.map
--------------------------------------------------------------------------------
/test/samples/transpile-concat-lowres/files/bundle.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "file": null,
4 | "sources": ["main.js", "placeholder.js"],
5 | "sourcesContent": [
6 | "/**\n * Copyright 2019 The AMP HTML Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nvar foo = function foo() {\n return 'foo';\n};\n/* PLACEHOLDER */\n\n\nvar baz = function baz() {\n return 'baz';\n};\n//# sourceMappingURL=main.js.map",
7 | "/**\n * Copyright 2019 The AMP HTML Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nvar bar = function bar() {\n return 'bar';\n};\n//# sourceMappingURL=placeholder.js.map"
8 | ],
9 | "names": [],
10 | "mappings": "AAAA;;;;;;;;;;;;;;;AAeA,IAAI,GAAG,GAAG,SAAS,GAAG,GAAG;EACvB,OAAO,KAAK,CAAC;CACd,CAAC;AACF;AClBA;;;;;;;;;;;;;;;AAeA,IAAI,GAAG,GAAG,SAAS,GAAG,GAAG;EACvB,OAAO,KAAK,CAAC;CACd,CAAC;;uCACqC,vCDAtB;;;AAGjB,IAAI,GAAG,GAAG,SAAS,GAAG,GAAG;EACvB,OAAO,KAAK,CAAC;CACd,CAAC;"
11 | }
12 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-lowres/files/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | var foo = function foo() {
17 | return 'foo';
18 | };
19 | /* PLACEHOLDER */
20 |
21 |
22 | var baz = function baz() {
23 | return 'baz';
24 | };
25 | //# sourceMappingURL=main.js.map
--------------------------------------------------------------------------------
/test/samples/transpile-concat-lowres/files/main.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "sources": ["main.mjs"],
4 | "names": ["foo", "baz"],
5 | "mappings": "AAAA;;;;;;;;;;;;;;;AAgBA,IAAMA,GAAG,GAAG,SAANA,GAAM;AAAA,SAAM,KAAN;AAAA,CAAZ;AACA;;;AACA,IAAMC,GAAG,GAAG,SAANA,GAAM;AAAA,SAAM,KAAN;AAAA,CAAZ",
6 | "sourcesContent": [
7 | "/**\n * Copyright 2019 The AMP HTML Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst foo = () => 'foo';\n/* PLACEHOLDER */\nconst baz = () => 'baz';\n"
8 | ],
9 | "file": "main.js"
10 | }
11 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-lowres/files/main.mjs:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | const foo = () => 'foo';
18 | /* PLACEHOLDER */
19 | const baz = () => 'baz';
20 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-lowres/files/placeholder.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | var bar = function bar() {
17 | return 'bar';
18 | };
19 | //# sourceMappingURL=placeholder.js.map
--------------------------------------------------------------------------------
/test/samples/transpile-concat-lowres/files/placeholder.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "sources": ["placeholder.mjs"],
4 | "names": ["bar"],
5 | "mappings": "AAAA;;;;;;;;;;;;;;;AAgBA,IAAMA,GAAG,GAAG,SAANA,GAAM;AAAA,SAAM,KAAN;AAAA,CAAZ",
6 | "sourcesContent": [
7 | "/**\n * Copyright 2019 The AMP HTML Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst bar = () => 'bar';\n"
8 | ],
9 | "file": "placeholder.js"
10 | }
11 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-lowres/files/placeholder.mjs:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | const bar = () => 'bar';
18 |
--------------------------------------------------------------------------------
/test/samples/transpile-concat-lowres/test.ts:
--------------------------------------------------------------------------------
1 | import { readFileSync } from 'fs';
2 | import type { RawSourceMap } from 'source-map';
3 | import { SourceMapConsumer } from 'source-map';
4 | import remapping from '../../../src/remapping';
5 |
6 | function read(filename: string): string {
7 | return readFileSync(`${__dirname}/files/${filename}`, 'utf8');
8 | }
9 |
10 | describe('transpile then concatenate', () => {
11 | test('concated sections point to source files', () => {
12 | const map = read('bundle.js.map');
13 | const remapped = remapping(map, (file) => {
14 | return file.endsWith('.mjs') ? null : read(`${file}.map`);
15 | });
16 |
17 | const consumer = new SourceMapConsumer(remapped as unknown as RawSourceMap);
18 |
19 | const foo = consumer.originalPositionFor({
20 | column: 11,
21 | line: 17,
22 | });
23 | expect(foo).toMatchObject({
24 | column: 18,
25 | line: 17,
26 | source: 'main.mjs',
27 | });
28 |
29 | const bar = consumer.originalPositionFor({
30 | column: 11,
31 | line: 36,
32 | });
33 | expect(bar).toMatchObject({
34 | column: 18,
35 | line: 17,
36 | source: 'placeholder.mjs',
37 | });
38 |
39 | const baz = consumer.originalPositionFor({
40 | column: 11,
41 | line: 43,
42 | });
43 | expect(baz).toMatchObject({
44 | column: 18,
45 | line: 19,
46 | source: 'main.mjs',
47 | });
48 | });
49 |
50 | test('inherits sourcesContent of original sources', () => {
51 | const map = read('bundle.js.map');
52 | const remapped = remapping(map, (file) => {
53 | return file.endsWith('.mjs') ? null : read(`${file}.map`);
54 | });
55 |
56 | expect(remapped.sourcesContent).toEqual([read('main.mjs'), read('placeholder.mjs')]);
57 | });
58 | });
59 |
--------------------------------------------------------------------------------
/test/samples/transpile-minify/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(false);
3 |
4 | return {
5 | presets: [['@babel/preset-env', { modules: false }]],
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/test/samples/transpile-minify/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | DIR=`dirname $0`
3 | NODE_BIN=`npm bin`
4 |
5 | rm "$DIR"/files/*.js*
6 |
7 | if [ ! -f "$NODE_BIN/babel" ]; then
8 | npm install --no-save @babel/cli @babel/preset-env
9 | fi
10 | "$NODE_BIN/babel" "$DIR/files" --config-file "./$DIR/babel.config.js" --source-maps -d "$DIR/files"
11 |
12 | npx terser "$DIR/files/helloworld.js" -c --source-map "base='$DIR/files',includeSources" --comments all -o "$DIR/files/helloworld.min.js"
13 | npx prettier "$DIR/files/*.map" --parser json --write
14 |
--------------------------------------------------------------------------------
/test/samples/transpile-minify/files/helloworld.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | self.AMP_CONFIG = {};
17 |
18 | var greet = function greet() {
19 | return alert("hello");
20 | };
21 |
22 | greet();
23 | //# sourceMappingURL=helloworld.js.map
--------------------------------------------------------------------------------
/test/samples/transpile-minify/files/helloworld.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "sources": ["helloworld.mjs"],
4 | "names": ["self", "AMP_CONFIG", "greet", "alert"],
5 | "mappings": "AAAA;;;;;;;;;;;;;;;AAgBAA,IAAI,CAACC,UAAL,GAAkB,EAAlB;;AAEA,IAAMC,KAAK,GAAG,SAARA,KAAQ;AAAA,SAAMC,KAAK,SAAX;AAAA,CAAd;;AAEAD,KAAK",
6 | "sourcesContent": [
7 | "/**\n * Copyright 2019 The AMP HTML Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nself.AMP_CONFIG = {};\n\nconst greet = () => alert(`hello`);\n\ngreet();"
8 | ],
9 | "file": "helloworld.js"
10 | }
11 |
--------------------------------------------------------------------------------
/test/samples/transpile-minify/files/helloworld.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | self.AMP_CONFIG={};var greet=function(){return alert("hello")};greet();
17 | //# sourceMappingURL=helloworld.js.map
--------------------------------------------------------------------------------
/test/samples/transpile-minify/files/helloworld.min.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "sources": ["helloworld.js"],
4 | "names": ["self", "AMP_CONFIG", "greet", "alert"],
5 | "mappings": ";;;;;;;;;;;;;;;AAeAA,KAAKC,WAAa,GAElB,IAAIC,MAAQ,WACV,OAAOC,MAAM,UAGfD",
6 | "sourcesContent": [
7 | "/**\n * Copyright 2019 The AMP HTML Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nself.AMP_CONFIG = {};\n\nvar greet = function greet() {\n return alert(\"hello\");\n};\n\ngreet();\n//# sourceMappingURL=helloworld.js.map"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/test/samples/transpile-minify/files/helloworld.mjs:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | self.AMP_CONFIG = {};
18 |
19 | const greet = () => alert(`hello`);
20 |
21 | greet();
--------------------------------------------------------------------------------
/test/samples/transpile-minify/test.ts:
--------------------------------------------------------------------------------
1 | import { readFileSync } from 'fs';
2 | import type { RawSourceMap } from 'source-map';
3 | import { SourceMapConsumer } from 'source-map';
4 | import remapping from '../../../src/remapping';
5 |
6 | function read(filename: string): string {
7 | return readFileSync(`${__dirname}/files/${filename}`, 'utf8');
8 | }
9 |
10 | describe('transpile then minify', () => {
11 | test('minify a transpiled source map', () => {
12 | const map = read('helloworld.min.js.map');
13 | const remapped = remapping(map, (file) => {
14 | return file.endsWith('.mjs') ? null : read(`${file}.map`);
15 | });
16 |
17 | const consumer = new SourceMapConsumer(remapped as unknown as RawSourceMap);
18 | const alert = consumer.originalPositionFor({
19 | column: 47,
20 | line: 16,
21 | });
22 | expect(alert).toEqual({
23 | column: 20,
24 | line: 19,
25 | name: 'alert',
26 | source: 'helloworld.mjs',
27 | });
28 | });
29 |
30 | test('inherits sourcesContent of original source', () => {
31 | const map = read('helloworld.min.js.map');
32 | const remapped = remapping(map, (file) => {
33 | return file.endsWith('.mjs') ? null : read(`${file}.map`);
34 | });
35 |
36 | expect(remapped.sourcesContent).toEqual([read('helloworld.mjs')]);
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/test/samples/transpile-rollup/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(false);
3 |
4 | return {
5 | presets: [['@babel/preset-env', { modules: false }]],
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/test/samples/transpile-rollup/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | DIR="$(dirname $0)"
3 | NODE_BIN=`npm bin`
4 |
5 | rm "$DIR"/files/*.js*
6 |
7 | if [ ! -f "$NODE_BIN/babel" ]; then
8 | npm install --no-save @babel/cli @babel/preset-env
9 | fi
10 | "$NODE_BIN/babel" "$DIR/files" --config-file "./$DIR/babel.config.js" --source-maps -d "$DIR/files"
11 |
12 | # Strip the sourceMappingURL to prevent rollup from auto collapsing sourcemaps
13 | for f in $DIR/files/*.js; do
14 | sed '$d' $f > $f.tmp
15 | mv $f.tmp $f
16 | done
17 |
18 | npx rollup -i "$DIR/files/index.js" -f cjs -o "$DIR/files/bundle.js" --sourcemap
19 | npx prettier "$DIR/files/*.map" --parser json --write
20 |
--------------------------------------------------------------------------------
/test/samples/transpile-rollup/files/a.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | export default (function () {
17 | return 'a';
18 | });
19 |
--------------------------------------------------------------------------------
/test/samples/transpile-rollup/files/a.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "sources": ["a.mjs"],
4 | "names": [],
5 | "mappings": "AAAA;;;;;;;;;;;;;;;AAgBA,gBAAe;AAAA,SAAM,GAAN;AAAA,CAAf",
6 | "sourcesContent": [
7 | "/**\n * Copyright 2019 The AMP HTML Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport default () => 'a';"
8 | ],
9 | "file": "a.js"
10 | }
11 |
--------------------------------------------------------------------------------
/test/samples/transpile-rollup/files/a.mjs:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | export default () => 'a';
--------------------------------------------------------------------------------
/test/samples/transpile-rollup/files/b.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | export default (function () {
17 | return 'b';
18 | });
19 |
--------------------------------------------------------------------------------
/test/samples/transpile-rollup/files/b.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "sources": ["b.mjs"],
4 | "names": [],
5 | "mappings": "AAAA;;;;;;;;;;;;;;;AAgBA,gBAAe;AAAA,SAAM,GAAN;AAAA,CAAf",
6 | "sourcesContent": [
7 | "/**\n * Copyright 2019 The AMP HTML Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport default () => 'b';"
8 | ],
9 | "file": "b.js"
10 | }
11 |
--------------------------------------------------------------------------------
/test/samples/transpile-rollup/files/b.mjs:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | export default () => 'b';
--------------------------------------------------------------------------------
/test/samples/transpile-rollup/files/bundle.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, '__esModule', { value: true });
4 |
5 | /**
6 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | var a = (function () {
21 | return 'a';
22 | });
23 |
24 | /**
25 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
26 | *
27 | * Licensed under the Apache License, Version 2.0 (the "License");
28 | * you may not use this file except in compliance with the License.
29 | * You may obtain a copy of the License at
30 | *
31 | * http://www.apache.org/licenses/LICENSE-2.0
32 | *
33 | * Unless required by applicable law or agreed to in writing, software
34 | * distributed under the License is distributed on an "AS IS" BASIS,
35 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
36 | * See the License for the specific language governing permissions and
37 | * limitations under the License.
38 | */
39 | var b = (function () {
40 | return 'b';
41 | });
42 |
43 | exports.a = a;
44 | exports.b = b;
45 | //# sourceMappingURL=bundle.js.map
46 |
--------------------------------------------------------------------------------
/test/samples/transpile-rollup/files/bundle.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "file": "bundle.js",
4 | "sources": ["a.js", "b.js"],
5 | "sourcesContent": [
6 | "/**\n * Copyright 2019 The AMP HTML Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nexport default (function () {\n return 'a';\n});\n",
7 | "/**\n * Copyright 2019 The AMP HTML Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nexport default (function () {\n return 'b';\n});\n"
8 | ],
9 | "names": [],
10 | "mappings": ";;;;AAAA;;;;;;;;;;;;;;;AAeA,QAAe,CAAC,YAAY;EAC1B,OAAO,GAAG,CAAC;CACZ,EAAE;;ACjBH;;;;;;;;;;;;;;;AAeA,QAAe,CAAC,YAAY;EAC1B,OAAO,GAAG,CAAC;CACZ,EAAE;;;;;"
11 | }
12 |
--------------------------------------------------------------------------------
/test/samples/transpile-rollup/files/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | export { default as a } from './a.js';
17 | export { default as b } from './b.js';
18 |
--------------------------------------------------------------------------------
/test/samples/transpile-rollup/files/index.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "sources": ["index.mjs"],
4 | "names": ["default", "a", "b"],
5 | "mappings": "AAAA;;;;;;;;;;;;;;;AAgBA,SAAQA,OAAO,IAAIC,CAAnB,QAA2B,QAA3B;AACA,SAAQD,OAAO,IAAIE,CAAnB,QAA2B,QAA3B",
6 | "sourcesContent": [
7 | "/**\n * Copyright 2019 The AMP HTML Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport {default as a} from './a.js';\nexport {default as b} from './b.js';"
8 | ],
9 | "file": "index.js"
10 | }
11 |
--------------------------------------------------------------------------------
/test/samples/transpile-rollup/files/index.mjs:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 The AMP HTML Authors. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | export {default as a} from './a.js';
18 | export {default as b} from './b.js';
--------------------------------------------------------------------------------
/test/samples/transpile-rollup/test.ts:
--------------------------------------------------------------------------------
1 | import { readFileSync } from 'fs';
2 | import type { RawSourceMap } from 'source-map';
3 | import { SourceMapConsumer } from 'source-map';
4 | import remapping from '../../../src/remapping';
5 |
6 | function read(filename: string): string {
7 | return readFileSync(`${__dirname}/files/${filename}`, 'utf8');
8 | }
9 |
10 | describe('transpile then concatenate', () => {
11 | test('concated sections point to source files', () => {
12 | const map = read('bundle.js.map');
13 | const remapped = remapping(map, (file) => {
14 | return file.endsWith('.mjs') ? null : read(`${file}.map`);
15 | });
16 |
17 | const consumer = new SourceMapConsumer(remapped as unknown as RawSourceMap);
18 |
19 | const a = consumer.originalPositionFor({
20 | column: 11,
21 | line: 21,
22 | });
23 | expect(a).toMatchObject({
24 | column: 21,
25 | line: 17,
26 | source: 'a.mjs',
27 | });
28 |
29 | const b = consumer.originalPositionFor({
30 | column: 11,
31 | line: 40,
32 | });
33 | expect(b).toMatchObject({
34 | column: 21,
35 | line: 17,
36 | source: 'b.mjs',
37 | });
38 | });
39 |
40 | test('inherits sourcesContent of original sources', () => {
41 | const map = read('bundle.js.map');
42 | const remapped = remapping(map, (file) => {
43 | return file.endsWith('.mjs') ? null : read(`${file}.map`);
44 | });
45 |
46 | expect(remapped.sourcesContent).toEqual([read('a.mjs'), read('b.mjs')]);
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/test/unit/build-source-map-tree.ts:
--------------------------------------------------------------------------------
1 | import buildSourceMapTree from '../../src/build-source-map-tree';
2 | import type { DecodedSourceMap, EncodedSourceMap } from '../../src/types';
3 |
4 | describe('buildSourceMapTree', () => {
5 | const rawMap: EncodedSourceMap = {
6 | mappings: 'AAAA',
7 | names: [],
8 | sources: ['helloworld.js'],
9 | sourcesContent: [null],
10 | version: 3,
11 | };
12 | const decodedMap: DecodedSourceMap = {
13 | ...rawMap,
14 | mappings: [[[0, 0, 0, 0]]],
15 | };
16 |
17 | test('calls loader for any needed sourcemap', () => {
18 | const loader = jest.fn(() => null);
19 | buildSourceMapTree(decodedMap, loader);
20 |
21 | expect(loader).toHaveBeenCalledTimes(1);
22 | expect(loader).toHaveBeenCalledWith('helloworld.js', expect.anything());
23 | });
24 |
25 | test('loader cannot be async', () => {
26 | // tslint:disable-next-line: no-any
27 | const loader = (): any => Promise.resolve(null);
28 | expect(() => {
29 | buildSourceMapTree(decodedMap, loader);
30 | }).toThrow();
31 | });
32 |
33 | test('creates OriginalSource if no sourcemap', () => {
34 | const tree = buildSourceMapTree(decodedMap, () => null);
35 | expect(tree.sources).toMatchObject([
36 | {
37 | source: 'helloworld.js',
38 | },
39 | ]);
40 | });
41 |
42 | test('creates OriginalSource with sourceContent', () => {
43 | const tree = buildSourceMapTree(
44 | {
45 | ...decodedMap,
46 | sourcesContent: ['1 + 1'],
47 | },
48 | () => null
49 | );
50 |
51 | expect(tree.sources).toMatchObject([
52 | {
53 | content: '1 + 1',
54 | },
55 | ]);
56 | });
57 |
58 | test('creates OriginalSource with null content if no sourceContent', () => {
59 | const tree = buildSourceMapTree(decodedMap, () => null);
60 | expect(tree.sources).toMatchObject([
61 | {
62 | content: null,
63 | },
64 | ]);
65 | });
66 |
67 | test('creates OriginalSource with null content if no sourcesContent', () => {
68 | const tree = buildSourceMapTree(
69 | {
70 | ...decodedMap,
71 | sourcesContent: undefined,
72 | },
73 | () => null
74 | );
75 |
76 | expect(tree.sources).toMatchObject([
77 | {
78 | content: null,
79 | },
80 | ]);
81 | });
82 |
83 | test('creates ignored OriginalSource with ignoreList', () => {
84 | const tree = buildSourceMapTree(
85 | {
86 | ...decodedMap,
87 | ignoreList: [0],
88 | },
89 | () => null
90 | );
91 |
92 | expect(tree.sources).toMatchObject([
93 | {
94 | ignore: true,
95 | },
96 | ]);
97 | });
98 |
99 | test('creates unignored OriginalSource if no ignoreList', () => {
100 | const tree = buildSourceMapTree(decodedMap, () => null);
101 | expect(tree.sources).toMatchObject([
102 | {
103 | ignore: false,
104 | },
105 | ]);
106 | });
107 |
108 | test('creates unignored OriginalSource with if no ignoreList', () => {
109 | const tree = buildSourceMapTree(
110 | {
111 | ...decodedMap,
112 | ignoreList: undefined,
113 | },
114 | () => null
115 | );
116 |
117 | expect(tree.sources).toMatchObject([
118 | {
119 | ignore: false,
120 | },
121 | ]);
122 | });
123 |
124 | test('recursively loads sourcemaps', () => {
125 | const loader = jest.fn();
126 | loader
127 | .mockReturnValueOnce({
128 | ...rawMap,
129 | sources: ['two.js'],
130 | })
131 | .mockReturnValue(null);
132 | const tree = buildSourceMapTree(decodedMap, loader);
133 |
134 | expect(tree.sources).toMatchObject([
135 | {
136 | sources: [
137 | {
138 | source: 'two.js',
139 | },
140 | ],
141 | },
142 | ]);
143 |
144 | expect(loader).toHaveBeenCalledTimes(2);
145 | expect(loader).toHaveBeenCalledWith('helloworld.js', expect.anything());
146 | expect(loader).toHaveBeenCalledWith('two.js', expect.anything());
147 | });
148 |
149 | test('calls loader with sourceRoot joined to source file', () => {
150 | const loader = jest.fn(() => null);
151 | buildSourceMapTree(
152 | {
153 | ...decodedMap,
154 | sourceRoot: 'https://foo.com/',
155 | },
156 | loader
157 | );
158 |
159 | expect(loader).toHaveBeenCalledTimes(1);
160 | expect(loader).toHaveBeenCalledWith('https://foo.com/helloworld.js', expect.anything());
161 | });
162 |
163 | test('original sources are relative to the tree path', () => {
164 | const loader = jest.fn();
165 | loader
166 | .mockReturnValueOnce({
167 | ...rawMap,
168 | file: 'helloworld.js',
169 | sourceRoot: 'https://foo.com/',
170 | sources: ['./assets/two.js'],
171 | })
172 | .mockReturnValueOnce({
173 | ...rawMap,
174 | file: 'two.js',
175 | // We need to support relative roots...
176 | sourceRoot: './deep/',
177 | sources: ['three.js'],
178 | })
179 | .mockReturnValue(null);
180 | const tree = buildSourceMapTree(decodedMap, loader);
181 |
182 | expect(tree.sources).toMatchObject([
183 | {
184 | // helloworld.js's map
185 | sources: [
186 | {
187 | // two.js's map
188 | sources: [
189 | {
190 | source: 'https://foo.com/assets/deep/three.js',
191 | },
192 | ],
193 | },
194 | ],
195 | },
196 | ]);
197 |
198 | expect(loader).toHaveBeenCalledTimes(3);
199 | expect(loader).toHaveBeenCalledWith('helloworld.js', expect.anything());
200 | expect(loader).toHaveBeenCalledWith('https://foo.com/assets/two.js', expect.anything());
201 | expect(loader).toHaveBeenCalledWith('https://foo.com/assets/deep/three.js', expect.anything());
202 | });
203 |
204 | describe('loader context', () => {
205 | describe('importer', () => {
206 | test('is empty for sources loaded from the root', () => {
207 | const loader = jest.fn();
208 | buildSourceMapTree(decodedMap, loader);
209 |
210 | expect(loader).toHaveBeenCalledTimes(1);
211 | expect(loader).toHaveBeenCalledWith(
212 | expect.anything(),
213 | expect.objectContaining({
214 | importer: '',
215 | })
216 | );
217 | });
218 |
219 | test('is parent for nested sources', () => {
220 | const loader = jest.fn();
221 | loader.mockReturnValueOnce({
222 | ...rawMap,
223 | sources: ['two.js'],
224 | });
225 | buildSourceMapTree(decodedMap, loader);
226 |
227 | expect(loader).toHaveBeenCalledTimes(2);
228 | expect(loader).toHaveBeenCalledWith(
229 | 'helloworld.js',
230 | expect.objectContaining({
231 | importer: '',
232 | })
233 | );
234 | expect(loader).toHaveBeenCalledWith(
235 | 'two.js',
236 | expect.objectContaining({
237 | importer: 'helloworld.js',
238 | })
239 | );
240 | });
241 | });
242 |
243 | describe('depty', () => {
244 | test('is 1 for sources loaded from the root', () => {
245 | const loader = jest.fn();
246 | buildSourceMapTree(
247 | {
248 | ...decodedMap,
249 | sources: ['first.js', 'second.js'],
250 | },
251 | loader
252 | );
253 |
254 | expect(loader).toHaveBeenCalledTimes(2);
255 | expect(loader).toHaveBeenCalledWith(
256 | 'first.js',
257 | expect.objectContaining({
258 | depth: 1,
259 | })
260 | );
261 | expect(loader).toHaveBeenCalledWith(
262 | 'second.js',
263 | expect.objectContaining({
264 | depth: 1,
265 | })
266 | );
267 | });
268 |
269 | test('is increased for nested sources', () => {
270 | const loader = jest.fn();
271 | loader.mockReturnValueOnce({
272 | ...rawMap,
273 | sources: ['two.js'],
274 | });
275 | buildSourceMapTree(
276 | {
277 | ...decodedMap,
278 | sources: ['first.js', 'second.js'],
279 | },
280 | loader
281 | );
282 |
283 | expect(loader).toHaveBeenCalledTimes(3);
284 | expect(loader).toHaveBeenCalledWith(
285 | 'first.js',
286 | expect.objectContaining({
287 | depth: 1,
288 | })
289 | );
290 | expect(loader).toHaveBeenCalledWith(
291 | 'two.js',
292 | expect.objectContaining({
293 | depth: 2,
294 | })
295 | );
296 | expect(loader).toHaveBeenCalledWith(
297 | 'second.js',
298 | expect.objectContaining({
299 | depth: 1,
300 | })
301 | );
302 | });
303 | });
304 |
305 | describe('source', () => {
306 | test('matches the loader source param', () => {
307 | const loader = jest.fn();
308 | buildSourceMapTree(decodedMap, loader);
309 |
310 | expect(loader).toHaveBeenCalledTimes(1);
311 | expect(loader).toHaveBeenCalledWith(
312 | 'helloworld.js',
313 | expect.objectContaining({
314 | source: 'helloworld.js',
315 | })
316 | );
317 | });
318 |
319 | test('can be overridden to change source of original file', () => {
320 | const loader = jest.fn();
321 | loader.mockImplementationOnce((s, ctx) => {
322 | expect(s).toBe('helloworld.js');
323 | ctx.source = 'bar/baz.js';
324 | });
325 |
326 | const tree = buildSourceMapTree(decodedMap, loader);
327 |
328 | expect(tree.sources).toMatchObject([
329 | {
330 | source: 'bar/baz.js',
331 | },
332 | ]);
333 | });
334 |
335 | test('can be overridden to change resolving location', () => {
336 | const loader = jest.fn();
337 | loader.mockImplementationOnce((s, ctx) => {
338 | expect(s).toBe('helloworld.js');
339 | ctx.source = 'bar/baz.js';
340 | return {
341 | ...rawMap,
342 | sources: ['two.js'],
343 | };
344 | });
345 |
346 | const tree = buildSourceMapTree(decodedMap, loader);
347 |
348 | expect(tree.sources).toMatchObject([
349 | {
350 | sources: [
351 | {
352 | source: 'bar/two.js',
353 | },
354 | ],
355 | },
356 | ]);
357 | });
358 | });
359 |
360 | describe('content', () => {
361 | test('can override the sourcesContent of parent map', () => {
362 | const loader = jest.fn();
363 | loader.mockImplementationOnce((s, ctx) => {
364 | expect(s).toBe('helloworld.js');
365 | ctx.content = 'override';
366 | });
367 |
368 | const tree = buildSourceMapTree(decodedMap, loader);
369 |
370 | expect(tree.sources).toMatchObject([
371 | {
372 | content: 'override',
373 | },
374 | ]);
375 | });
376 |
377 | test('can override the sourcesContent of parent map', () => {
378 | const loader = jest.fn();
379 | loader.mockImplementationOnce((s, ctx) => {
380 | expect(s).toBe('helloworld.js');
381 | ctx.content = null;
382 | });
383 |
384 | const tree = buildSourceMapTree(
385 | {
386 | ...decodedMap,
387 | sourcesContent: ['test'],
388 | },
389 | loader
390 | );
391 |
392 | expect(tree.sources).toMatchObject([
393 | {
394 | content: null,
395 | },
396 | ]);
397 | });
398 | });
399 |
400 | describe('ignore', () => {
401 | test('can override the ignore of parent map', () => {
402 | const loader = jest.fn();
403 | loader.mockImplementationOnce((s, ctx) => {
404 | expect(s).toBe('helloworld.js');
405 | ctx.ignore = true;
406 | });
407 |
408 | const tree = buildSourceMapTree(decodedMap, loader);
409 |
410 | expect(tree.sources).toMatchObject([
411 | {
412 | ignore: true,
413 | },
414 | ]);
415 | });
416 |
417 | test('can override the sourcesContent of parent map', () => {
418 | const loader = jest.fn();
419 | loader.mockImplementationOnce((s, ctx) => {
420 | expect(s).toBe('helloworld.js');
421 | ctx.ignore = false;
422 | });
423 |
424 | const tree = buildSourceMapTree(
425 | {
426 | ...decodedMap,
427 | ignoreList: [0],
428 | },
429 | loader
430 | );
431 |
432 | expect(tree.sources).toMatchObject([
433 | {
434 | ignore: false,
435 | },
436 | ]);
437 | });
438 | });
439 | });
440 |
441 | test('original sources are relative to the tree path, edge cases', () => {
442 | const loader = jest.fn();
443 | loader
444 | .mockReturnValueOnce({
445 | ...rawMap,
446 | file: 'helloworld.js',
447 | sources: ['/two.js'],
448 | })
449 | .mockReturnValueOnce({
450 | ...rawMap,
451 | file: 'two.js',
452 | // We need to support relative roots...
453 | // sourceRoot: './assets/',
454 | sources: ['./assets/three.js'],
455 | })
456 | .mockReturnValue(null);
457 | const tree = buildSourceMapTree(
458 | {
459 | ...decodedMap,
460 | // We shouldn't need this, but we need absolute URLs because our resolver
461 | // sucks.
462 | sourceRoot: 'https://foo.com/deep',
463 | },
464 | loader
465 | );
466 |
467 | expect(tree.sources).toMatchObject([
468 | {
469 | // helloworld.js's map
470 | sources: [
471 | {
472 | // two.js's map
473 | sources: [
474 | {
475 | source: 'https://foo.com/assets/three.js',
476 | },
477 | ],
478 | },
479 | ],
480 | },
481 | ]);
482 |
483 | expect(loader).toHaveBeenCalledTimes(3);
484 | expect(loader).toHaveBeenCalledWith('https://foo.com/deep/helloworld.js', expect.anything());
485 | expect(loader).toHaveBeenCalledWith('https://foo.com/two.js', expect.anything());
486 | expect(loader).toHaveBeenCalledWith('https://foo.com/assets/three.js', expect.anything());
487 | });
488 |
489 | describe('array form', () => {
490 | test('transformation maps of a sourcemap may be passed before the sourcemap', () => {
491 | const maps = [
492 | decodedMap, // "transformation map"
493 | decodedMap,
494 | ];
495 | const tree = buildSourceMapTree(maps, () => null);
496 |
497 | expect(tree.sources).toMatchObject([
498 | {
499 | // helloworld.js's map
500 | sources: [
501 | {
502 | source: 'helloworld.js',
503 | },
504 | ],
505 | },
506 | ]);
507 | });
508 |
509 | test('transformation map does not influence map url', () => {
510 | const maps = [
511 | {
512 | ...decodedMap,
513 | sourceRoot: 'https://example.com/',
514 | }, // "transformation map"
515 | decodedMap,
516 | ];
517 | const tree = buildSourceMapTree(maps, () => null);
518 |
519 | expect(tree.sources).toMatchObject([
520 | {
521 | // helloworld.js's map
522 | sources: [
523 | {
524 | source: 'helloworld.js',
525 | },
526 | ],
527 | },
528 | ]);
529 | });
530 |
531 | test('throws when transformation map has more than one source', () => {
532 | const maps = [
533 | {
534 | ...decodedMap,
535 | sources: ['one.js', 'two.js'],
536 | }, // "transformation map"
537 | decodedMap,
538 | ];
539 |
540 | expect(() => {
541 | buildSourceMapTree(maps, () => null);
542 | }).toThrow();
543 | });
544 |
545 | test('handles when transformation map has 0 sources', () => {
546 | const maps = [
547 | {
548 | ...decodedMap,
549 | mappings: [],
550 | sources: [],
551 | }, // "transformation map"
552 | decodedMap,
553 | ];
554 | const loader = jest.fn();
555 |
556 | const tree = buildSourceMapTree(maps, loader);
557 | expect(tree.map).toMatchObject({
558 | sources: [],
559 | });
560 | expect(loader).toHaveBeenCalledTimes(1);
561 | expect(loader).toHaveBeenCalledWith('helloworld.js', expect.anything());
562 | });
563 | });
564 |
565 | describe('null source', () => {
566 | test('parses map with null source', () => {
567 | const loader = jest.fn();
568 | loader
569 | .mockReturnValueOnce({
570 | ...rawMap,
571 | sources: ['two.js'],
572 | })
573 | .mockReturnValue(null);
574 | const tree = buildSourceMapTree(
575 | {
576 | ...decodedMap,
577 | sources: [null],
578 | },
579 | loader
580 | );
581 |
582 | expect(tree.map).toMatchObject({
583 | sources: [null],
584 | });
585 |
586 | expect(loader).toHaveBeenCalledWith('', expect.anything());
587 | });
588 |
589 | test('parses maps descending from null source', () => {
590 | const loader = jest.fn();
591 | loader
592 | .mockReturnValueOnce({
593 | ...rawMap,
594 | sources: ['two.js'],
595 | })
596 | .mockReturnValue(null);
597 | const tree = buildSourceMapTree(
598 | {
599 | ...decodedMap,
600 | sources: [null],
601 | },
602 | loader
603 | );
604 |
605 | expect(tree.sources).toMatchObject([
606 | {
607 | sources: [
608 | {
609 | source: 'two.js',
610 | },
611 | ],
612 | },
613 | ]);
614 |
615 | expect(loader).toHaveBeenCalledWith('', expect.anything());
616 | expect(loader).toHaveBeenCalledWith('two.js', expect.anything());
617 | });
618 |
619 | test('parses maps descending from null source with sourceRoot', () => {
620 | const loader = jest.fn();
621 | loader
622 | .mockReturnValueOnce({
623 | ...rawMap,
624 | sources: ['two.js'],
625 | })
626 | .mockReturnValue(null);
627 | const tree = buildSourceMapTree(
628 | {
629 | ...decodedMap,
630 | sourceRoot: 'https://foo.com/',
631 | sources: [null],
632 | },
633 | loader
634 | );
635 |
636 | expect(tree.sources).toMatchObject([
637 | {
638 | sources: [
639 | {
640 | source: 'https://foo.com/two.js',
641 | },
642 | ],
643 | },
644 | ]);
645 |
646 | expect(loader).toHaveBeenCalledWith('https://foo.com/', expect.anything());
647 | expect(loader).toHaveBeenCalledWith('https://foo.com/two.js', expect.anything());
648 | });
649 | });
650 | });
651 |
--------------------------------------------------------------------------------
/test/unit/remapping.ts:
--------------------------------------------------------------------------------
1 | import remapping from '../../src/remapping';
2 | import type { EncodedSourceMap } from '../../src/types';
3 |
4 | describe('remapping', () => {
5 | const rawMap: EncodedSourceMap = {
6 | file: 'transpiled.min.js',
7 | // 0th column of 1st line of output file translates into the 1st source
8 | // file, line 2, column 1, using 1st name.
9 | mappings: 'AACCA',
10 | names: ['add'],
11 | sources: ['transpiled.js'],
12 | sourcesContent: ['1+1'],
13 | version: 3,
14 | ignoreList: [],
15 | };
16 | const transpiledMap: EncodedSourceMap = {
17 | // 1st column of 2nd line of output file translates into the 1st source
18 | // file, line 3, column 2
19 | mappings: ';CAEE',
20 | names: [],
21 | sources: ['helloworld.js'],
22 | sourcesContent: ['\n\n 1 + 1;'],
23 | version: 3,
24 | ignoreList: [],
25 | };
26 | const translatedMap: EncodedSourceMap = {
27 | file: 'transpiled.min.js',
28 | // 0th column of 1st line of output file translates into the 1st source
29 | // file, line 3, column 2, using first name
30 | mappings: 'AAEEA',
31 | names: ['add'],
32 | // TODO: support sourceRoot
33 | // sourceRoot: '',
34 | sources: ['helloworld.js'],
35 | sourcesContent: ['\n\n 1 + 1;'],
36 | version: 3,
37 | ignoreList: [],
38 | };
39 |
40 | test('does not alter a lone sourcemap', () => {
41 | const map = remapping(rawMap, () => null);
42 | expect(map).toEqual(rawMap);
43 | });
44 |
45 | test('traces SourceMapSegments through child sourcemaps', () => {
46 | const map = remapping(rawMap, (name: string) => {
47 | if (name === 'transpiled.js') {
48 | return transpiledMap;
49 | }
50 | });
51 |
52 | expect(map).toEqual(translatedMap);
53 | });
54 |
55 | test('traces transformations through sourcemap', () => {
56 | const maps = [rawMap, transpiledMap];
57 | const map = remapping(maps, () => null);
58 |
59 | expect(map).toEqual(translatedMap);
60 | });
61 |
62 | test('resolves sourcemaps realtive to sourceRoot', () => {
63 | const sourceRoot = 'foo/';
64 | const map = remapping(
65 | {
66 | ...rawMap,
67 | sourceRoot,
68 | },
69 | (name: string) => {
70 | if (name.endsWith('transpiled.js')) {
71 | return transpiledMap;
72 | }
73 | }
74 | );
75 |
76 | expect(map).toEqual({
77 | ...translatedMap,
78 | // TODO: support sourceRoot
79 | // sourceRoot,
80 | sources: ['foo/helloworld.js'],
81 | });
82 | });
83 |
84 | test('resolves sourcemaps realtive to absolute sourceRoot', () => {
85 | const sourceRoot = 'https://foo.com/';
86 | const map = remapping(
87 | {
88 | ...rawMap,
89 | sourceRoot,
90 | },
91 | (name: string) => {
92 | if (name.endsWith('transpiled.js')) {
93 | return transpiledMap;
94 | }
95 | }
96 | );
97 |
98 | expect(map).toEqual({
99 | ...translatedMap,
100 | // TODO: support sourceRoot
101 | // sourceRoot,
102 | sources: [`${sourceRoot}helloworld.js`],
103 | });
104 | });
105 |
106 | test('includes null sourceContent if sourcemap has no sourcesContent', () => {
107 | const map = remapping(rawMap, (name: string) => {
108 | if (name === 'transpiled.js') {
109 | return {
110 | ...transpiledMap,
111 | sourcesContent: undefined,
112 | };
113 | }
114 | });
115 |
116 | expect(map).toHaveProperty('sourcesContent', [null]);
117 | });
118 |
119 | test('excludes null sourceContent if sourcemap is not self-containing', () => {
120 | const map = remapping(rawMap, (name: string) => {
121 | if (name === 'transpiled.js') {
122 | return {
123 | ...transpiledMap,
124 | sourcesContent: [null],
125 | };
126 | }
127 | });
128 |
129 | expect(map).toHaveProperty('sourcesContent', [null]);
130 | });
131 |
132 | test('ignores if original source is ignored', () => {
133 | const map = remapping(rawMap, (name: string) => {
134 | if (name === 'transpiled.js') {
135 | return {
136 | ...transpiledMap,
137 | ignoreList: [0],
138 | };
139 | }
140 | });
141 |
142 | expect(map).toHaveProperty('ignoreList', [0]);
143 | });
144 |
145 | test('unignores if sourcemap has no ignoreList', () => {
146 | const map = remapping(rawMap, (name: string) => {
147 | if (name === 'transpiled.js') {
148 | return {
149 | ...transpiledMap,
150 | ignoreList: undefined,
151 | };
152 | }
153 | });
154 |
155 | expect(map).toHaveProperty('ignoreList', []);
156 | });
157 |
158 | test('unignores if sourcemap unignores original source', () => {
159 | const map = remapping(rawMap, (name: string) => {
160 | if (name === 'transpiled.js') {
161 | return {
162 | ...transpiledMap,
163 | ignoreList: [],
164 | };
165 | }
166 | });
167 |
168 | expect(map).toHaveProperty('ignoreList', []);
169 | });
170 |
171 | describe('boolean options', () => {
172 | test('excludes sourcesContent if `excludeContent` is set', () => {
173 | const map = remapping(
174 | rawMap,
175 | (name: string) => {
176 | if (name === 'transpiled.js') {
177 | return transpiledMap;
178 | }
179 | },
180 | true
181 | );
182 |
183 | expect(map).not.toHaveProperty('sourcesContent');
184 | });
185 | });
186 |
187 | describe('options bag', () => {
188 | test('excludes sourcesContent if `excludeContent` is set', () => {
189 | const map = remapping(
190 | rawMap,
191 | (name: string) => {
192 | if (name === 'transpiled.js') {
193 | return transpiledMap;
194 | }
195 | },
196 | { excludeContent: true }
197 | );
198 |
199 | expect(map).not.toHaveProperty('sourcesContent');
200 | });
201 |
202 | test('returns decoded sourcemap if `decodedMappings` is set', () => {
203 | const map = remapping(
204 | rawMap,
205 | (name: string) => {
206 | if (name === 'transpiled.js') {
207 | return transpiledMap;
208 | }
209 | },
210 | { decodedMappings: true }
211 | );
212 |
213 | expect(map).toHaveProperty('mappings', [[[0, 0, 2, 2, 0]]]);
214 | });
215 | });
216 | });
217 |
--------------------------------------------------------------------------------
/test/unit/source-map-tree.ts:
--------------------------------------------------------------------------------
1 | import { toDecodedMap } from '@jridgewell/gen-mapping';
2 | import { TraceMap } from '@jridgewell/trace-mapping';
3 |
4 | import {
5 | OriginalSource,
6 | MapSource,
7 | originalPositionFor,
8 | traceMappings,
9 | } from '../../src/source-map-tree';
10 | import type { DecodedSourceMap } from '../../src/types';
11 |
12 | describe('MapSource', () => {
13 | describe('traceMappings()', () => {
14 | const sourceRoot = 'foo';
15 | const baseMap: DecodedSourceMap = {
16 | mappings: [],
17 | names: ['name'],
18 | sourceRoot,
19 | sources: ['child.js'],
20 | version: 3,
21 | };
22 | const child = MapSource(
23 | new TraceMap({
24 | mappings: [
25 | [
26 | [0, 0, 0, 0],
27 | [1, 0, 0, 0],
28 | [2, 0, 0, 0],
29 | [4, 0, 1, 1],
30 | ], // line 0
31 | [[1, 0, 0, 0, 0], [6]], // line 1
32 | ],
33 | names: ['child'],
34 | sources: ['original.js'],
35 | version: 3,
36 | }),
37 | [OriginalSource(`${sourceRoot}/original.js`, '', false)]
38 | );
39 |
40 | test('records segment if segment is 1-length', () => {
41 | const map: DecodedSourceMap = {
42 | ...baseMap,
43 | mappings: [[[0, 0, 0, 4], [5]]],
44 | };
45 |
46 | const tree = MapSource(new TraceMap(map), [child]);
47 | const traced = toDecodedMap(traceMappings(tree));
48 | expect(traced.mappings).toEqual([[[0, 0, 1, 1], [5]]]);
49 | });
50 |
51 | test('records segment if trace hits 1-length segment', () => {
52 | const map: DecodedSourceMap = {
53 | ...baseMap,
54 | mappings: [
55 | [
56 | [0, 0, 0, 4],
57 | [5, 0, 1, 6],
58 | ],
59 | ],
60 | };
61 |
62 | const tree = MapSource(new TraceMap(map), [child]);
63 | const traced = toDecodedMap(traceMappings(tree));
64 | expect(traced.mappings).toEqual([[[0, 0, 1, 1], [5]]]);
65 | });
66 |
67 | test('skips segment if trace returns null', () => {
68 | const sourceIndex = 0;
69 | const line = 10; // There is no line 10 in child's mappings.
70 | const column = 0;
71 | const map: DecodedSourceMap = {
72 | ...baseMap,
73 | mappings: [[[0, sourceIndex, line, column]]],
74 | };
75 |
76 | const tree = MapSource(new TraceMap(map), [child]);
77 | const traced = toDecodedMap(traceMappings(tree));
78 | expect(traced.mappings).toEqual([]);
79 | });
80 |
81 | test('traces name if segment is 5-length', () => {
82 | const sourceIndex = 0;
83 | const line = 0;
84 | const column = 0;
85 | const nameIndex = 0;
86 | const name = 'name';
87 | const map: DecodedSourceMap = {
88 | ...baseMap,
89 | mappings: [[[0, sourceIndex, line, column, nameIndex]]],
90 | names: [name],
91 | };
92 |
93 | const tree = MapSource(new TraceMap(map), [child]);
94 | const traced = toDecodedMap(traceMappings(tree));
95 | expect(traced.mappings).toEqual([[[0, 0, 0, 0, 0]]]);
96 | expect(traced).toMatchObject({
97 | names: [name],
98 | });
99 | });
100 |
101 | test('maps into traced segment', () => {
102 | const sourceIndex = 0;
103 | const line = 0;
104 | const column = 4;
105 | const map: DecodedSourceMap = {
106 | ...baseMap,
107 | mappings: [[[0, sourceIndex, line, column]]],
108 | };
109 |
110 | const tree = MapSource(new TraceMap(map), [child]);
111 | const traced = toDecodedMap(traceMappings(tree));
112 | expect(traced.mappings).toEqual([[[0, 0, 1, 1]]]);
113 | });
114 |
115 | test('maps into traced segment with name', () => {
116 | const sourceIndex = 0;
117 | const line = 1;
118 | const column = 1;
119 | const map: DecodedSourceMap = {
120 | ...baseMap,
121 | mappings: [[[0, sourceIndex, line, column]]],
122 | };
123 |
124 | const tree = MapSource(new TraceMap(map), [child]);
125 | const traced = toDecodedMap(traceMappings(tree));
126 | expect(traced.mappings).toEqual([[[0, 0, 0, 0, 0]]]);
127 | expect(traced).toMatchObject({
128 | names: ['child'],
129 | });
130 | });
131 |
132 | test('defaults decoded return map with original data', () => {
133 | const extras = {
134 | file: 'foobar.js',
135 | // TODO: support sourceRoot
136 | // sourceRoot: 'https://foobar.com/',
137 | };
138 | const map: DecodedSourceMap = {
139 | ...baseMap,
140 | mappings: [],
141 | ...extras,
142 | };
143 |
144 | const tree = MapSource(new TraceMap(map), [child]);
145 | const traced = toDecodedMap(traceMappings(tree));
146 | expect(traced).toMatchObject(extras);
147 | });
148 |
149 | test('resolves source files realtive to sourceRoot', () => {
150 | const map: DecodedSourceMap = {
151 | ...baseMap,
152 | mappings: [[[0, 0, 0, 0]]],
153 | };
154 |
155 | const tree = MapSource(new TraceMap(map), [child]);
156 | const traced = toDecodedMap(traceMappings(tree));
157 | expect(traced).toMatchObject({
158 | // TODO: support sourceRoot
159 | sourceRoot: undefined,
160 | sources: ['foo/original.js'],
161 | });
162 | });
163 |
164 | test('truncates mappings to the last line with segment', () => {
165 | const map: DecodedSourceMap = {
166 | ...baseMap,
167 | mappings: [[[0, 0, 0, 0]], [], []],
168 | sourceRoot,
169 | };
170 |
171 | const tree = MapSource(new TraceMap(map), [child]);
172 | const traced = toDecodedMap(traceMappings(tree));
173 | expect(traced.mappings).toEqual([[[0, 0, 0, 0]]]);
174 | });
175 |
176 | test('truncates empty mappings', () => {
177 | const map: DecodedSourceMap = {
178 | ...baseMap,
179 | mappings: [[], [], []],
180 | sourceRoot,
181 | };
182 |
183 | const tree = MapSource(new TraceMap(map), [child]);
184 | const traced = toDecodedMap(traceMappings(tree));
185 | expect(traced.mappings).toEqual([]);
186 | });
187 |
188 | describe('redundant segments', () => {
189 | it('skips redundant segments on the same line', () => {
190 | const map: DecodedSourceMap = {
191 | ...baseMap,
192 | mappings: [
193 | [
194 | [0, 0, 0, 0],
195 | [1, 0, 0, 0],
196 | ],
197 | ],
198 | };
199 |
200 | const tree = MapSource(new TraceMap(map), [child]);
201 | const traced = toDecodedMap(traceMappings(tree));
202 | expect(traced.mappings).toEqual([[[0, 0, 0, 0]]]);
203 | });
204 |
205 | it('keeps redundant segments on another line', () => {
206 | const map: DecodedSourceMap = {
207 | ...baseMap,
208 | mappings: [[[0, 0, 0, 0]], [[0, 0, 0, 0]]],
209 | };
210 |
211 | const tree = MapSource(new TraceMap(map), [child]);
212 | const traced = toDecodedMap(traceMappings(tree));
213 | expect(traced.mappings).toEqual([[[0, 0, 0, 0]], [[0, 0, 0, 0]]]);
214 | });
215 | });
216 | });
217 |
218 | describe('originalPositionFor()', () => {
219 | const map: DecodedSourceMap = {
220 | mappings: [
221 | [
222 | [0, 0, 0, 0],
223 | [1, 0, 0, 0],
224 | [2, 0, 0, 0],
225 | [4, 0, 1, 1],
226 | ], // line 0
227 | [[2, 0, 0, 0]], // line 1 - maps to line 0 col 0
228 | [[0]], // line 2 has 1 length segment
229 | [[0, 0, 0, 0, 0]], // line 3 has a name
230 | [
231 | [0, 0, 4, 0],
232 | [5, 0, 4, 6],
233 | ], // line 4 is identical to line 4 of source except col 5 was removed eg 01234567890 -> 012346789
234 | [[0, 0, 5, 0], [5], [6, 0, 5, 5]], // line 4 is identical to line 4 of source except a char was added at col 5 eg 01234*56789 -> 0123*456789
235 | ],
236 | names: ['name'],
237 | sources: ['child.js'],
238 | version: 3,
239 | };
240 | const tree = MapSource(new TraceMap(map), [OriginalSource('child.js', '', false)]);
241 |
242 | test('traces LineSegments to the segment with matching generated column', () => {
243 | const trace = originalPositionFor(tree, 0, 4, '');
244 | expect(trace).toMatchObject({ line: 1, column: 1 });
245 | });
246 |
247 | test('traces all generated cols on a line back to their source when source had characters removed', () => {
248 | const expectedCols = [0, 0, 0, 0, 0, 6, 6, 6, 6];
249 | for (let genCol = 0; genCol < expectedCols.length; genCol++) {
250 | const trace = originalPositionFor(tree, 4, genCol, '');
251 | expect(trace).toMatchObject({ line: 4, column: expectedCols[genCol] });
252 | }
253 | });
254 |
255 | test('traces all generated cols on a line back to their source when source had characters added', () => {
256 | const expectedCols = [0, 0, 0, 0, 0, null, 5, 5, 5, 5, 5];
257 | for (let genCol = 0; genCol < expectedCols.length; genCol++) {
258 | const trace = originalPositionFor(tree, 5, genCol, '');
259 | if (expectedCols[genCol] == null) {
260 | expect(trace).toMatchObject({ source: '' });
261 | } else {
262 | expect(trace).toMatchObject({ line: 5, column: expectedCols[genCol] });
263 | }
264 | }
265 | });
266 |
267 | test('returns null if line is longer than mapping lines', () => {
268 | const trace = originalPositionFor(tree, 10, 0, '');
269 | expect(trace).toBe(null);
270 | });
271 |
272 | test('returns null if no matching segment column', () => {
273 | //line 1 col 0 of generated doesn't exist in the original source
274 | const trace = originalPositionFor(tree, 1, 0, '');
275 | expect(trace).toBe(null);
276 | });
277 |
278 | test('returns sourceless segment object if segment is 1-length', () => {
279 | const trace = originalPositionFor(tree, 2, 0, '');
280 | expect(trace).toMatchObject({ source: '' });
281 | });
282 |
283 | test('passes in outer name to trace', () => {
284 | const trace = originalPositionFor(tree, 0, 0, 'foo');
285 | expect(trace).toMatchObject({ name: 'foo' });
286 | });
287 |
288 | test('overrides name if segment is 5-length', () => {
289 | const trace = originalPositionFor(tree, 3, 0, 'foo');
290 | expect(trace).toMatchObject({ name: 'name' });
291 | });
292 |
293 | describe('tracing same line multiple times', () => {
294 | describe('later column', () => {
295 | test('returns matching segment after match', () => {
296 | expect(originalPositionFor(tree, 0, 1, '')).not.toBe(null);
297 | const trace = originalPositionFor(tree, 0, 4, '');
298 | expect(trace).toMatchObject({ line: 1, column: 1 });
299 | });
300 |
301 | test('returns matching segment after null match', () => {
302 | expect(originalPositionFor(tree, 1, 0, '')).toBe(null);
303 | const trace = originalPositionFor(tree, 1, 2, '');
304 | expect(trace).toMatchObject({ line: 0, column: 0 });
305 | });
306 |
307 | test('returns null segment segment after null match', () => {
308 | expect(originalPositionFor(tree, 1, 0, '')).toBe(null);
309 | const trace = originalPositionFor(tree, 1, 1, '');
310 | expect(trace).toBe(null);
311 | });
312 |
313 | test('returns matching segment after almost match', () => {
314 | expect(originalPositionFor(tree, 4, 2, '')).not.toBe(null);
315 | const trace = originalPositionFor(tree, 4, 5, '');
316 | expect(trace).toMatchObject({ line: 4, column: 6 });
317 | });
318 | });
319 |
320 | describe('earlier column', () => {
321 | test('returns matching segment after match', () => {
322 | expect(originalPositionFor(tree, 0, 4, '')).not.toBe(null);
323 | const trace = originalPositionFor(tree, 0, 1, '');
324 | expect(trace).toMatchObject({ line: 0, column: 0 });
325 | });
326 |
327 | test('returns null segment segment after null match', () => {
328 | expect(originalPositionFor(tree, 1, 1, '')).toBe(null);
329 | const trace = originalPositionFor(tree, 1, 0, '');
330 | expect(trace).toBe(null);
331 | });
332 |
333 | test('returns matching segment after almost match', () => {
334 | expect(originalPositionFor(tree, 4, 2, '')).not.toBe(null);
335 | const trace = originalPositionFor(tree, 4, 0, '');
336 | expect(trace).toMatchObject({ line: 4, column: 0 });
337 | });
338 | });
339 | });
340 | });
341 | });
342 |
--------------------------------------------------------------------------------
/test/unit/source-map.ts:
--------------------------------------------------------------------------------
1 | import { GenMapping, addSegment, setIgnore, setSourceContent } from '@jridgewell/gen-mapping';
2 | import SourceMap from '../../src/source-map';
3 |
4 | describe('SourceMap', () => {
5 | const opts = {
6 | excludeContent: false,
7 | decodedMappings: false,
8 | };
9 |
10 | test('it is a compliant, v3 sourcemap', () => {
11 | const traced = new GenMapping();
12 | addSegment(traced, 0, 0, 'file.js', 0, 0, '');
13 |
14 | const map = new SourceMap(traced, opts);
15 | expect(map).toHaveProperty('mappings', 'AAAA');
16 | expect(map).toHaveProperty('names', []);
17 | expect(map).toHaveProperty('sources', ['file.js']);
18 | expect(map).toHaveProperty('version', 3);
19 | });
20 |
21 | test('it can include a file', () => {
22 | const file = 'foobar.js';
23 | const traced = new GenMapping({ file });
24 | addSegment(traced, 0, 0, 'file.js', 0, 0, '');
25 |
26 | const map = new SourceMap(traced, opts);
27 | expect(map).toHaveProperty('file', file);
28 | });
29 |
30 | // TODO: support sourceRoot
31 | test.skip('it can include a sourceRoot', () => {
32 | const sourceRoot = 'https://foo.com/';
33 | const traced = new GenMapping({ sourceRoot });
34 | addSegment(traced, 0, 0, 'file.js', 0, 0, '');
35 |
36 | const map = new SourceMap(traced, opts);
37 | expect(map).toHaveProperty('sourceRoot', sourceRoot);
38 | });
39 |
40 | test('it can include a sourcesContent', () => {
41 | const content = '1 + 1';
42 | const traced = new GenMapping();
43 | addSegment(traced, 0, 0, 'file.js', 0, 0, '');
44 | setSourceContent(traced, 'file.js', content);
45 |
46 | const map = new SourceMap(traced, opts);
47 | expect(map).toHaveProperty('sourcesContent', [content]);
48 | });
49 |
50 | test('sourcesContent can be manually excluded', () => {
51 | const content = '1 + 1';
52 | const traced = new GenMapping();
53 | addSegment(traced, 0, 0, 'file.js', 0, 0, '');
54 | setSourceContent(traced, 'file.js', content);
55 |
56 | const map = new SourceMap(traced, { ...opts, excludeContent: true });
57 | expect(map).not.toHaveProperty('sourcesContent');
58 | });
59 |
60 | test('it can include ignoreList', () => {
61 | const traced = new GenMapping();
62 | addSegment(traced, 0, 0, 'file.js', 0, 0, '');
63 | setIgnore(traced, 'file.js');
64 |
65 | const map = new SourceMap(traced, opts);
66 | expect(map).toHaveProperty('ignoreList', [0]);
67 | });
68 |
69 | test('mappings can be decoded', () => {
70 | const traced = new GenMapping();
71 | addSegment(traced, 0, 0, 'file.js', 0, 0, '');
72 |
73 | const map = new SourceMap(traced, { ...opts, decodedMappings: true });
74 | expect(map).toHaveProperty('mappings', [[[0, 0, 0, 0]]]);
75 | });
76 |
77 | describe('toString()', () => {
78 | test('returns the sourcemap in JSON', () => {
79 | const traced = new GenMapping();
80 | addSegment(traced, 0, 0, 'file.js', 0, 0, '');
81 |
82 | const map = new SourceMap(traced, opts);
83 | expect(JSON.parse(map.toString())).toEqual(map);
84 | });
85 | });
86 | });
87 |
--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "emitDeclarationOnly": true,
5 | "rootDir": "src"
6 | },
7 | "include": [
8 | "src"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "moduleResolution": "node",
4 | "esModuleInterop": true,
5 | "target": "es2015",
6 | "module": "es2015",
7 | "lib": ["es2015"],
8 | "strict": true,
9 | "sourceMap": true,
10 | "inlineSources": true,
11 | "declaration": true,
12 | "allowSyntheticDefaultImports": true,
13 | "declarationDir": "dist/types",
14 | "typeRoots": ["node_modules/@types"]
15 | },
16 | "exclude": ["dist"],
17 | "include": ["src", "test"]
18 | }
19 |
--------------------------------------------------------------------------------