• Stars
    star
    100
  • Rank 330,009 (Top 7 %)
  • Language
    TypeScript
  • License
    Apache License 2.0
  • Created almost 5 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Remap sequential sourcemaps through transformations to point at the original source code

@ampproject/remapping

Remap sequential sourcemaps through transformations to point at the original source code

Remapping allows you to take the sourcemaps generated through transforming your code and "remap" them to the original source locations. Think "my minified code, transformed with babel and bundled with webpack", all pointing to the correct location in your original source code.

With remapping, none of your source code transformations need to be aware of the input's sourcemap, they only need to generate an output sourcemap. This greatly simplifies building custom transformations (think a find-and-replace).

Installation

npm install @ampproject/remapping

Usage

function remapping(
  map: SourceMap | SourceMap[],
  loader: (file: string, ctx: LoaderContext) => (SourceMap | null | undefined),
  options?: { excludeContent: boolean, decodedMappings: boolean }
): SourceMap;

// LoaderContext gives the loader the importing sourcemap, tree depth, the ability to override the
// "source" location (where child sources are resolved relative to, or the location of original
// source), and the ability to override the "content" of an original source for inclusion in the
// output sourcemap.
type LoaderContext = {
 readonly importer: string;
 readonly depth: number;
 source: string;
 content: string | null | undefined;
}

remapping takes the final output sourcemap, and a loader function. For every source file pointer in the sourcemap, the loader will be called with the resolved path. If the path itself represents a transformed file (it has a sourcmap associated with it), then the loader should return that sourcemap. If not, the path will be treated as an original, untransformed source code.

// Babel transformed "helloworld.js" into "transformed.js"
const transformedMap = JSON.stringify({
  file: 'transformed.js',
  // 1st column of 2nd line of output file translates into the 1st source
  // file, line 3, column 2
  mappings: ';CAEE',
  sources: ['helloworld.js'],
  version: 3,
});

// Uglify minified "transformed.js" into "transformed.min.js"
const minifiedTransformedMap = JSON.stringify({
  file: 'transformed.min.js',
  // 0th column of 1st line of output file translates into the 1st source
  // file, line 2, column 1.
  mappings: 'AACC',
  names: [],
  sources: ['transformed.js'],
  version: 3,
});

const remapped = remapping(
  minifiedTransformedMap,
  (file, ctx) => {

    // The "transformed.js" file is an transformed file.
    if (file === 'transformed.js') {
      // The root importer is empty.
      console.assert(ctx.importer === '');
      // The depth in the sourcemap tree we're currently loading.
      // The root `minifiedTransformedMap` is depth 0, and its source children are depth 1, etc.
      console.assert(ctx.depth === 1);

      return transformedMap;
    }

    // Loader will be called to load transformedMap's source file pointers as well.
    console.assert(file === 'helloworld.js');
    // `transformed.js`'s sourcemap points into `helloworld.js`.
    console.assert(ctx.importer === 'transformed.js');
    // This is a source child of `transformed`, which is a source child of `minifiedTransformedMap`.
    console.assert(ctx.depth === 2);
    return null;
  }
);

console.log(remapped);
// {
//   file: 'transpiled.min.js',
//   mappings: 'AAEE',
//   sources: ['helloworld.js'],
//   version: 3,
// };

In this example, loader will be called twice:

  1. "transformed.js", the first source file pointer in the minifiedTransformedMap. We return the associated sourcemap for it (its a transformed file, after all) so that sourcemap locations can be traced through it into the source files it represents.
  2. "helloworld.js", our original, unmodified source code. This file does not have a sourcemap, so we return null.

The remapped sourcemap now points from transformed.min.js into locations in helloworld.js. If you were to read the mappings, it says "0th column of the first line output line points to the 1st column of the 2nd line of the file helloworld.js".

Multiple transformations of a file

As a convenience, if you have multiple single-source transformations of a file, you may pass an array of sourcemap files in the order of most-recent transformation sourcemap first. Note that this changes the importer and depth of each call to our loader. So our above example could have been written as:

const remapped = remapping(
  [minifiedTransformedMap, transformedMap],
  () => null
);

console.log(remapped);
// {
//   file: 'transpiled.min.js',
//   mappings: 'AAEE',
//   sources: ['helloworld.js'],
//   version: 3,
// };

Advanced control of the loading graph

source

The source property can overridden to any value to change the location of the current load. Eg, for an original source file, it allows us to change the location to the original source regardless of what the sourcemap source entry says. And for transformed files, it allows us to change the relative resolving location for child sources of the loaded sourcemap.

const remapped = remapping(
  minifiedTransformedMap,
  (file, ctx) => {

    if (file === 'transformed.js') {
      // We pretend the transformed.js file actually exists in the 'src/' directory. When the nested
      // source files are loaded, they will now be relative to `src/`.
      ctx.source = 'src/transformed.js';
      return transformedMap;
    }

    console.assert(file === 'src/helloworld.js');
    // We could futher change the source of this original file, eg, to be inside a nested directory
    // itself. This will be reflected in the remapped sourcemap.
    ctx.source = 'src/nested/transformed.js';
    return null;
  }
);

console.log(remapped);
// {
//   …,
//   sources: ['src/nested/helloworld.js'],
// };

content

The content property can be overridden when we encounter an original source file. Eg, this allows you to manually provide the source content of the original file regardless of whether the sourcesContent field is present in the parent sourcemap. It can also be set to null to remove the source content.

const remapped = remapping(
  minifiedTransformedMap,
  (file, ctx) => {

    if (file === 'transformed.js') {
      // transformedMap does not include a `sourcesContent` field, so usually the remapped sourcemap
      // would not include any `sourcesContent` values.
      return transformedMap;
    }

    console.assert(file === 'helloworld.js');
    // We can read the file to provide the source content.
    ctx.content = fs.readFileSync(file, 'utf8');
    return null;
  }
);

console.log(remapped);
// {
//   …,
//   sourcesContent: [
//     'console.log("Hello world!")',
//   ],
// };

Options

excludeContent

By default, excludeContent is false. Passing { excludeContent: true } will exclude the sourcesContent field from the returned sourcemap. This is mainly useful when you want to reduce the size out the sourcemap.

decodedMappings

By default, decodedMappings is false. Passing { decodedMappings: true } will leave the mappings field in a decoded state instead of encoding into a VLQ string.

More Repositories

1

amphtml

The AMP web component framework.
JavaScript
14,883
star
2

worker-dom

The same DOM API and Frameworks you know, but in a Web Worker.
TypeScript
3,169
star
3

amp-wp

Enable AMP on your WordPress site, the WordPress way.
PHP
1,783
star
4

amp-by-example

DEPRECATED: AMP by Example has been merged into amp.dev
HTML
754
star
5

amp.dev

The AMP Project Website.
HTML
577
star
6

amp-toolbox

A collection of AMP tools making it easier to publish and host AMP pages.
HTML
450
star
7

samples

HTML
444
star
8

ampstart

AMP Start source code and templates .
HTML
420
star
9

rollup-plugin-closure-compiler

Leverage Closure Compiler to minify and optimize JavaScript with Rollup.
TypeScript
291
star
10

amppackager

Tool to improve AMP URLs via Signed Exchanges
Go
139
star
11

meta

Information about the AMP open source project.
75
star
12

filesize

Monitor the size of files in your project specified within package.json.
TypeScript
75
star
13

amp-toolbox-php

AMP Optimizer PHP library
PHP
72
star
14

amp-sw

A drop in service worker library to help your AMP pages gain network resiliency in 1 line
JavaScript
70
star
15

ampbench

AMPBench: AMP URL validation and troubleshooting tools (DEPRECATED)
JavaScript
67
star
16

wg-amp4email

Responsible for the AMP4Email project. Facilitator: @nainar
54
star
17

bentojs.dev

Bento Website
SCSS
49
star
18

eleventy-plugin-amp

Quickly build interactive websites with Eleventy & AMP.
JavaScript
45
star
19

amp-viewer

Objective-C
39
star
20

bento

An easy to use component library that helps you achieve a great page experience
37
star
21

amp-react-prototype

A scratch pad to experiment with React rendered AMP Components
JavaScript
36
star
22

amp-github-apps

GitHub Apps for the AMP Project
JavaScript
35
star
23

wg-stories

Responsible for implementing and improving AMP's story format (amp-story). Facilitator: @newmuis
28
star
24

meta-ac

The AMP Advisory Committee
24
star
25

animations

TypeScript
23
star
26

cloudflare-amp-optimizer

Implementation of AMP Optimizer for Cloudflare Workers
JavaScript
22
star
27

design-docs

Design docs contributed to AMP.
20
star
28

wg-bento

JavaScript
17
star
29

amp-react

JavaScript
17
star
30

amp-email-viewer

TypeScript
16
star
31

wg-outreach

Responsible for helping developers who use AMP remain productive and keeping the AMP community healthy. This includes maintaining and enhancing AMP's developer-facing sites and documentation, maintaining communication channels, organizing community events, etc. Facilitator: @sebastianbenz
JavaScript
15
star
32

meta-tsc

The AMP Technical Steering Committee
14
star
33

amp-readiness

AMP Readiness is a chrome extension allows you to quickly see what technologies used on the page are AMP compatible.
JavaScript
14
star
34

error-tracker

AMP Project's error logging server
JavaScript
13
star
35

wg-components

Responsible for AMP components, the overall health of AMP Pages, analytics features, and integrations with partner technologies. Facilitator: @alanorozco
11
star
36

wg-access-subscriptions

Responsible for user specific controlled access to AMP content (amp-subscriptions, amp-access and related extensions) Facilitator: @jpettitt Slack: #wg-access-subs
11
star
37

cdn-worker

CDN worker source code
TypeScript
10
star
38

amphtml-build-artifacts

This repository contains build artifacts related to the ampproject/amphtml project
10
star
39

bento-compiler

Server-render AMP Components with worker-dom
HTML
9
star
40

validator-java

A validator for the AMP HTML format implemented in Java
Java
9
star
41

wg-monetization

Responsible for monetization features and integrations in AMP. Facilitator: @powerivq
8
star
42

wg-caching

Responsible for AMP's validator and features related to AMP caches. Facilitator: @Gregable
8
star
43

px-toolbox-php

PHP
8
star
44

storybook-addon-amp

The storybook AMP addon
TypeScript
8
star
45

cdn-configuration

Configuration settings for AMP Project CDNs
TypeScript
7
star
46

wg-performance

Monitoring and improving AMP's load and runtime performance for compliant documents. Facilitator: @erwinmombay
7
star
47

amp-status

HTML
7
star
48

wg-analytics

Deprecated Working Group, previously responsible for analytics features.
6
star
49

amp-wp-qa-tester

Easily test pre-release versions of the AMP Plugin for WordPress.
PHP
6
star
50

wg-viewers

Responsible for ensuring support for AMP viewers and for the amp-viewer project. Facilitator: @gmajoulet
5
star
51

amp-closure-compiler

JavaScript
5
star
52

wg-runtime

Responsible for AMP's core runtime, such as layout/rendering and data binding. Facilitator: @jridgewell
4
star
53

wg-infra

Responsible for AMP's infrastructure, including building, testing and release. Facilitator: @danielrozenberg
4
star
54

wg-codeofconduct

Responsible for enforcing AMP's Code of Conduct. (The Technical Steering Committee delegates its responsibility for enforcement of the Code of Conduct to this Working Group.) Facilitator: @nainar
3
star
55

npw

A workspace-aware npm wrapper to aid with developing in monorepos
JavaScript
3
star
56

wg-approvers

Responsible for approving changes that have a significant impact on AMP's behavior or significant new features as described in the feature and bug fix process. Facilitator: @dvoytenko
3
star
57

wg-foundation-onboarding

Responsible for work/coordination related to AMP completing the OpenJS Foundation onboarding
3
star
58

error-reporting

Contains production error tracking issues.
2
star
59

wg-security-privacy

2
star