From 58ba7fc07518afdacb5363b6449fadfedc0ad6d7 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Fri, 28 Apr 2017 12:25:44 -0700 Subject: [PATCH] Unify source map types Summary: deduplicates / unifies types for source maps across the code base Reviewed By: jeanlauliac Differential Revision: D4955924 fbshipit-source-id: 25cb71031dce835dd7d2bc1c27d6b20050906e81 --- flow/babel.js.flow | 9 +++-- local-cli/bundle/output/bundle.js | 5 ++- local-cli/bundle/output/unbundle/util.js | 22 ++++------- local-cli/bundle/types.flow.js | 4 +- packager/src/Bundler/Bundle.js | 23 ++++++------ packager/src/Bundler/source-map/Generator.js | 6 +-- packager/src/JSTransformer/index.js | 6 +-- .../JSTransformer/worker/constant-folding.js | 4 +- packager/src/JSTransformer/worker/inline.js | 6 +-- packager/src/JSTransformer/worker/worker.js | 6 +-- packager/src/ModuleGraph/output/source-map.js | 30 ++------------- packager/src/ModuleGraph/types.flow.js | 6 +-- packager/src/Resolver/index.js | 12 +++--- .../src/Server/symbolicate/symbolicate.js | 2 +- packager/src/lib/ModuleTransport.js | 4 +- packager/src/lib/SourceMap.js | 37 +++++++++++-------- packager/src/lib/TransformCache.js | 6 +-- packager/src/lib/relativizeSourceMap.js | 10 +++-- packager/src/node-haste/Module.js | 4 +- 19 files changed, 92 insertions(+), 110 deletions(-) diff --git a/flow/babel.js.flow b/flow/babel.js.flow index 9dc2bd0b660..1bb25d0b1b3 100644 --- a/flow/babel.js.flow +++ b/flow/babel.js.flow @@ -8,12 +8,13 @@ */ type _SourceMap = { - version: number, file?: string, - sources: Array, - names: Array, mappings: string, - sourcesContent?: Array, + names: Array, + sourceRoot?: string, + sources: Array, + sourcesContent?: Array, + version: number, }; // based on babylon v6.13.1 diff --git a/local-cli/bundle/output/bundle.js b/local-cli/bundle/output/bundle.js index 0b1487f3c4d..0db6abd36c3 100644 --- a/local-cli/bundle/output/bundle.js +++ b/local-cli/bundle/output/bundle.js @@ -17,7 +17,8 @@ const meta = require('./meta'); const relativizeSourceMap = require('../../../packager/src//lib/relativizeSourceMap'); const writeFile = require('./writeFile'); -import type Bundle from '../../../packager/src//Bundler/Bundle'; +import type Bundle from '../../../packager/src/Bundler/Bundle'; +import type {SourceMap} from '../../../packager/src/lib/SourceMap'; import type {OutputOptions, RequestOptions} from '../types.flow'; function buildBundle(packagerClient: Server, requestOptions: RequestOptions) { @@ -31,7 +32,7 @@ function buildBundle(packagerClient: Server, requestOptions: RequestOptions) { function createCodeWithMap(bundle: Bundle, dev: boolean, sourceMapSourcesRoot?: string): * { const map = bundle.getSourceMap({dev}); const sourceMap = relativizeSourceMap( - typeof map === 'string' ? JSON.parse(map) : map, + typeof map === 'string' ? (JSON.parse(map): SourceMap) : map, sourceMapSourcesRoot); return { code: bundle.getSource({dev}), diff --git a/local-cli/bundle/output/unbundle/util.js b/local-cli/bundle/output/unbundle/util.js index 802f1981ab8..6974f3eb7e1 100644 --- a/local-cli/bundle/output/unbundle/util.js +++ b/local-cli/bundle/output/unbundle/util.js @@ -12,14 +12,15 @@ const invariant = require('fbjs/lib/invariant'); -import type {ModuleGroups, ModuleTransportLike, SourceMap} from '../../types.flow'; +import type {IndexMap, MappingsMap, SourceMap} from '../../../../packager/src/lib/SourceMap'; +import type {ModuleGroups, ModuleTransportLike} from '../../types.flow'; const newline = /\r\n?|\n|\u2028|\u2029/g; // fastest implementation const countLines = (string: string) => (string.match(newline) || []).length + 1; -function lineToLineSourceMap(source: string, filename: string = ''): SourceMap { +function lineToLineSourceMap(source: string, filename: string = ''): MappingsMap { // The first line mapping in our package is the base64vlq code for zeros (A). const firstLine = 'AAAA;'; @@ -52,19 +53,12 @@ function combineSourceMaps({ moduleGroups, modules, withCustomOffsets, -}: CombineSourceMapsOptions): SourceMap { - let offsets; +}: CombineSourceMapsOptions): IndexMap { + const offsets = []; const sections = []; - const sourceMap: Object = { - file: '', - sections, - version: 3, - }; - - - if (withCustomOffsets) { - offsets = sourceMap.x_facebook_offsets = []; - } + const sourceMap: IndexMap = withCustomOffsets + ? {sections, version: 3, x_facebook_offsets: offsets} + : {sections, version: 3}; let line = 0; modules.forEach(moduleTransport => { diff --git a/local-cli/bundle/types.flow.js b/local-cli/bundle/types.flow.js index 714c797978e..8f74bf12e58 100644 --- a/local-cli/bundle/types.flow.js +++ b/local-cli/bundle/types.flow.js @@ -13,9 +13,9 @@ import type Bundle from '../../packager/src/Bundler/Bundle'; import type {Unbundle} from '../../packager/src/Bundler/Bundle'; import type ModuleTransport from '../../packager/src/lib/ModuleTransport'; -import type {MixedSourceMap} from '../../packager/src/lib/SourceMap'; +import type {FBSourceMap, SourceMap} from '../../packager/src/lib/SourceMap'; -export type {Bundle, ModuleTransport, MixedSourceMap as SourceMap, Unbundle}; +export type {Bundle, FBSourceMap, ModuleTransport, SourceMap, Unbundle}; export type ModuleGroups = {| groups: Map>, diff --git a/packager/src/Bundler/Bundle.js b/packager/src/Bundler/Bundle.js index 582853ec202..45d130e731f 100644 --- a/packager/src/Bundler/Bundle.js +++ b/packager/src/Bundler/Bundle.js @@ -20,8 +20,9 @@ const debug = require('debug')('RNP:Bundle'); const invariant = require('fbjs/lib/invariant'); const {fromRawMappings} = require('./source-map'); +const {isMappingsMap} = require('../lib/SourceMap'); -import type {SourceMap, CombinedSourceMap, MixedSourceMap} from '../lib/SourceMap'; +import type {IndexMap, MappingsMap, SourceMap} from '../lib/SourceMap'; import type {GetSourceOptions, FinalizeOptions} from './BundleBase'; export type Unbundle = { @@ -206,7 +207,7 @@ class Bundle extends BundleBase { * that makes use of of the `sections` field to combine sourcemaps by adding * an offset. This is supported only by Chrome for now. */ - _getCombinedSourceMaps(options: {excludeSource?: boolean}): CombinedSourceMap { + _getCombinedSourceMaps(options: {excludeSource?: boolean}): IndexMap { const result = { version: 3, file: this._getSourceMapFile(), @@ -215,22 +216,22 @@ class Bundle extends BundleBase { let line = 0; this.getModules().forEach(module => { - let map = module.map == null || module.virtual + invariant( + !Array.isArray(module.map), + `Unexpected raw mappings for ${module.sourcePath}`, + ); + let map: SourceMap = module.map == null || module.virtual ? generateSourceMapForVirtualModule(module) : module.map; - invariant( - !Array.isArray(map), - `Unexpected raw mappings for ${module.sourcePath}`, - ); - if (options.excludeSource && 'sourcesContent' in map) { + if (options.excludeSource && isMappingsMap(map)) { map = {...map, sourcesContent: []}; } result.sections.push({ offset: {line, column: 0}, - map: (map: MixedSourceMap), + map: map, }); line += module.code.split('\n').length; }); @@ -238,7 +239,7 @@ class Bundle extends BundleBase { return result; } - getSourceMap(options: {excludeSource?: boolean}): MixedSourceMap { + getSourceMap(options: {excludeSource?: boolean}): SourceMap { this.assertFinalized(); return this._sourceMapFormat === 'indexed' @@ -314,7 +315,7 @@ class Bundle extends BundleBase { } } -function generateSourceMapForVirtualModule(module): SourceMap { +function generateSourceMapForVirtualModule(module): MappingsMap { // All lines map 1-to-1 let mappings = 'AAAA;'; diff --git a/packager/src/Bundler/source-map/Generator.js b/packager/src/Bundler/source-map/Generator.js index 35427c8b24d..cce6a1d2870 100644 --- a/packager/src/Bundler/source-map/Generator.js +++ b/packager/src/Bundler/source-map/Generator.js @@ -13,7 +13,7 @@ const B64Builder = require('./B64Builder'); -import type {SourceMap} from 'babel-core'; +import type {MappingsMap} from '../../lib/SourceMap'; /** * Generates a source map from raw mappings. @@ -39,7 +39,7 @@ class Generator { names: IndexedSet; source: number; sources: Array; - sourcesContent: Array; + sourcesContent: Array; constructor() { this.builder = new B64Builder(); @@ -141,7 +141,7 @@ class Generator { /** * Return the source map as object. */ - toMap(file?: string): SourceMap { + toMap(file?: string): MappingsMap { return { version: 3, file, diff --git a/packager/src/JSTransformer/index.js b/packager/src/JSTransformer/index.js index 6cc7e56e17d..a084bbce028 100644 --- a/packager/src/JSTransformer/index.js +++ b/packager/src/JSTransformer/index.js @@ -21,7 +21,7 @@ const util = require('util'); const workerFarm = require('worker-farm'); import type {Data as TransformData, Options as TransformOptions} from './worker/worker'; -import type {SourceMap} from '../lib/SourceMap'; +import type {MappingsMap} from '../lib/SourceMap'; // Avoid memory leaks caused in workers. This number seems to be a good enough number // to avoid any memory leak while not slowing down initial builds. @@ -62,8 +62,8 @@ class Transformer { minify: ( filename: string, code: string, - sourceMap: SourceMap, - ) => Promise<{code: string, map: SourceMap}>; + sourceMap: MappingsMap, + ) => Promise<{code: string, map: MappingsMap}>; constructor(transformModulePath: string, maxWorkerCount: number) { invariant(path.isAbsolute(transformModulePath), 'transform module path should be absolute'); diff --git a/packager/src/JSTransformer/worker/constant-folding.js b/packager/src/JSTransformer/worker/constant-folding.js index 3ab0b1d296e..36cfbf62c94 100644 --- a/packager/src/JSTransformer/worker/constant-folding.js +++ b/packager/src/JSTransformer/worker/constant-folding.js @@ -13,7 +13,7 @@ const babel = require('babel-core'); -import type {Ast, SourceMap} from 'babel-core'; +import type {Ast, SourceMap as MappingsMap} from 'babel-core'; const t = babel.types; const Conditional = { @@ -73,7 +73,7 @@ const plugin = { function constantFolding(filename: string, transformResult: { ast: Ast, code?: ?string, - map: ?SourceMap, + map: ?MappingsMap, }) { return babel.transformFromAst(transformResult.ast, transformResult.code, { filename, diff --git a/packager/src/JSTransformer/worker/inline.js b/packager/src/JSTransformer/worker/inline.js index 9952f229072..6094a7cb629 100644 --- a/packager/src/JSTransformer/worker/inline.js +++ b/packager/src/JSTransformer/worker/inline.js @@ -14,7 +14,7 @@ const babel = require('babel-core'); const invariant = require('fbjs/lib/invariant'); -import type {Ast, SourceMap} from 'babel-core'; +import type {Ast, SourceMap as MappingsMap} from 'babel-core'; const t = babel.types; const React = {name: 'React'}; @@ -164,12 +164,12 @@ function checkRequireArgs(args, dependencyId) { type AstResult = { ast: Ast, code: ?string, - map: ?SourceMap, + map: ?MappingsMap, }; function inline( filename: string, - transformResult: {ast?: ?Ast, code: string, map: ?SourceMap}, + transformResult: {ast?: ?Ast, code: string, map: ?MappingsMap}, options: {+dev: boolean, +platform: string}, ): AstResult { const code = transformResult.code; diff --git a/packager/src/JSTransformer/worker/worker.js b/packager/src/JSTransformer/worker/worker.js index a3e978206e0..5c437810059 100644 --- a/packager/src/JSTransformer/worker/worker.js +++ b/packager/src/JSTransformer/worker/worker.js @@ -18,13 +18,13 @@ const invariant = require('fbjs/lib/invariant'); const minify = require('./minify'); import type {LogEntry} from '../../Logger/Types'; -import type {Ast, SourceMap} from 'babel-core'; +import type {Ast, SourceMap as MappingsMap} from 'babel-core'; export type TransformedCode = { code: string, dependencies: Array, dependencyOffsets: Array, - map?: ?SourceMap, + map?: ?MappingsMap, }; type Transformer = { @@ -32,7 +32,7 @@ type Transformer = { filename: string, sourceCode: string, options: ?{}, - ) => {ast: ?Ast, code: string, map: ?SourceMap} + ) => {ast: ?Ast, code: string, map: ?MappingsMap} }; export type TransformOptions = {| diff --git a/packager/src/ModuleGraph/output/source-map.js b/packager/src/ModuleGraph/output/source-map.js index bade8fec24a..7f45ac9cfb9 100644 --- a/packager/src/ModuleGraph/output/source-map.js +++ b/packager/src/ModuleGraph/output/source-map.js @@ -10,37 +10,15 @@ */ 'use strict'; +import type {FBSourceMap, IndexMapSection, IndexMap} from '../../lib/SourceMap'; + +export type {FBSourceMap}; + type CreateIndexMapOptions = {| file?: string, sections?: Array |}; -type IndexMap = MapBase & { - sections: Array, -}; - -type IndexMapSection = { - map: IndexMap | MappingsMap, - offset: {line: number, column: number}, -}; - -type MapBase = { - // always the first entry in the source map entry object per - // https://fburl.com/source-map-spec#heading=h.qz3o9nc69um5 - version: 3, - file?: string, -}; - -type MappingsMap = MapBase & { - mappings: string, - names: Array, - sourceRoot?: string, - sources: Array, - sourcesContent?: Array, -}; - -export type SourceMap = IndexMap | MappingsMap; - exports.createIndexMap = (opts?: CreateIndexMapOptions): IndexMap => ({ version: 3, file: opts && opts.file, diff --git a/packager/src/ModuleGraph/types.flow.js b/packager/src/ModuleGraph/types.flow.js index fd27309e3b8..1e250df02d6 100644 --- a/packager/src/ModuleGraph/types.flow.js +++ b/packager/src/ModuleGraph/types.flow.js @@ -10,7 +10,7 @@ */ 'use strict'; -import type {SourceMap} from './output/source-map'; +import type {MappingsMap, SourceMap} from '../lib/SourceMap'; import type {Ast} from 'babel-core'; import type {Console} from 'console'; @@ -102,7 +102,7 @@ type ResolveOptions = { export type TransformerResult = {| ast: ?Ast, code: string, - map: ?SourceMap, + map: ?MappingsMap, |}; export type Transformer = { @@ -111,7 +111,7 @@ export type Transformer = { filename: string, options: ?{}, plugins?: Array, - ) => {ast: ?Ast, code: string, map: ?SourceMap} + ) => {ast: ?Ast, code: string, map: ?MappingsMap} }; export type TransformResult = {| diff --git a/packager/src/Resolver/index.js b/packager/src/Resolver/index.js index 4613050b2c1..f96ab0822f3 100644 --- a/packager/src/Resolver/index.js +++ b/packager/src/Resolver/index.js @@ -18,14 +18,14 @@ const pathJoin = require('path').join; import type ResolutionResponse from '../node-haste/DependencyGraph/ResolutionResponse'; import type Module, {HasteImpl, TransformCode} from '../node-haste/Module'; -import type {SourceMap} from '../lib/SourceMap'; +import type {MappingsMap} from '../lib/SourceMap'; import type {Options as JSTransformerOptions} from '../JSTransformer/worker/worker'; import type {Reporter} from '../lib/reporting'; import type {GetTransformCacheKey} from '../lib/TransformCache'; import type {GlobalTransformCache} from '../lib/GlobalTransformCache'; -type MinifyCode = (filePath: string, code: string, map: SourceMap) => - Promise<{code: string, map: SourceMap}>; +type MinifyCode = (filePath: string, code: string, map: MappingsMap) => + Promise<{code: string, map: MappingsMap}>; type ContainsTransformerOptions = {+transformer: JSTransformerOptions} @@ -195,7 +195,7 @@ class Resolver { resolutionResponse: ResolutionResponse, module: Module, name: string, - map: SourceMap, + map: MappingsMap, code: string, meta?: { dependencyOffsets?: Array, @@ -227,8 +227,8 @@ class Resolver { } minifyModule( - {path, code, map}: {path: string, code: string, map: SourceMap}, - ): Promise<{code: string, map: SourceMap}> { + {path, code, map}: {path: string, code: string, map: MappingsMap}, + ): Promise<{code: string, map: MappingsMap}> { return this._minifyCode(path, code, map); } diff --git a/packager/src/Server/symbolicate/symbolicate.js b/packager/src/Server/symbolicate/symbolicate.js index 5fbb5ac1443..3ea3c08979c 100644 --- a/packager/src/Server/symbolicate/symbolicate.js +++ b/packager/src/Server/symbolicate/symbolicate.js @@ -20,7 +20,7 @@ const {LazyPromise, LockingPromise} = require('./util'); const {fork} = require('child_process'); export type {SourceMap as SourceMap}; -import type {MixedSourceMap as SourceMap} from '../../lib/SourceMap'; +import type {SourceMap} from '../../lib/SourceMap'; export type Stack = Array<{file: string, lineNumber: number, column: number}>; export type Symbolicate = diff --git a/packager/src/lib/ModuleTransport.js b/packager/src/lib/ModuleTransport.js index 840de0e9595..1c4e48bdd86 100644 --- a/packager/src/lib/ModuleTransport.js +++ b/packager/src/lib/ModuleTransport.js @@ -12,9 +12,9 @@ 'use strict'; import type {RawMapping} from '../Bundler/source-map'; -import type {MixedSourceMap} from './SourceMap'; +import type {SourceMap} from './SourceMap'; -type SourceMapOrMappings = MixedSourceMap | Array; +type SourceMapOrMappings = SourceMap | Array; type Metadata = { dependencies?: ?Array, diff --git a/packager/src/lib/SourceMap.js b/packager/src/lib/SourceMap.js index d356cddb94a..afbce1016ec 100644 --- a/packager/src/lib/SourceMap.js +++ b/packager/src/lib/SourceMap.js @@ -11,23 +11,28 @@ 'use strict'; -import type {SourceMap as BabelSourceMap} from 'babel-core'; +import type {SourceMap as MappingsMap} from 'babel-core'; -export type SourceMap = BabelSourceMap; - -export type CombinedSourceMap = { - version: number, - file?: string, - sections: Array<{ - offset: {line: number, column: number}, - map: MixedSourceMap, - }>, +export type IndexMapSection = { + map: SourceMap, + offset: {line: number, column: number}, }; -type FBExtensions = {x_facebook_offsets?: Array}; +type FBExtensions = {x_facebook_offsets: Array}; -export type MixedSourceMap - = SourceMap - | CombinedSourceMap - | (SourceMap & FBExtensions) - | (CombinedSourceMap & FBExtensions); +export type {MappingsMap}; +export type IndexMap = { + file?: string, + mappings?: void, // avoids SourceMap being a disjoint union + sections: Array, + version: number, +}; + +export type SourceMap = IndexMap | MappingsMap; +export type FBSourceMap = (IndexMap & FBExtensions) | (MappingsMap & FBExtensions); + +function isMappingsMap(map: SourceMap)/*: %checks*/ { + return map.mappings !== undefined; +} + +exports.isMappingsMap = isMappingsMap; diff --git a/packager/src/lib/TransformCache.js b/packager/src/lib/TransformCache.js index 64d4c3dd2ca..652ba7d96db 100644 --- a/packager/src/lib/TransformCache.js +++ b/packager/src/lib/TransformCache.js @@ -21,7 +21,7 @@ const terminal = require('../lib/terminal'); const writeFileAtomicSync = require('write-file-atomic').sync; import type {Options as TransformOptions} from '../JSTransformer/worker/worker'; -import type {SourceMap} from './SourceMap'; +import type {MappingsMap} from './SourceMap'; import type {Reporter} from './reporting'; type CacheFilePaths = {transformedCode: string, metadata: string}; @@ -94,7 +94,7 @@ export type CachedResult = { code: string, dependencies: Array, dependencyOffsets: Array, - map?: ?SourceMap, + map?: ?MappingsMap, }; export type TransformCacheResult = {| @@ -281,7 +281,7 @@ function readMetadataFileSync( cachedSourceHash: string, dependencies: Array, dependencyOffsets: Array, - sourceMap: ?SourceMap, + sourceMap: ?MappingsMap, } { const metadataStr = fs.readFileSync(metadataFilePath, 'utf8'); let metadata; diff --git a/packager/src/lib/relativizeSourceMap.js b/packager/src/lib/relativizeSourceMap.js index 4b9050d83d6..28f35b49531 100644 --- a/packager/src/lib/relativizeSourceMap.js +++ b/packager/src/lib/relativizeSourceMap.js @@ -13,10 +13,12 @@ const path = require('path'); -import type {MixedSourceMap} from './SourceMap'; +const {isMappingsMap} = require('./SourceMap'); -function relativizeSourceMapInternal(sourceMap: any, sourcesRoot: string) { - if (sourceMap.sections) { +import type {SourceMap} from './SourceMap'; + +function relativizeSourceMapInternal(sourceMap: SourceMap, sourcesRoot: string) { + if (!isMappingsMap(sourceMap)) { for (let i = 0; i < sourceMap.sections.length; i++) { relativizeSourceMapInternal(sourceMap.sections[i].map, sourcesRoot); } @@ -27,7 +29,7 @@ function relativizeSourceMapInternal(sourceMap: any, sourcesRoot: string) { } } -function relativizeSourceMap(sourceMap: MixedSourceMap, sourcesRoot?: string): MixedSourceMap { +function relativizeSourceMap(sourceMap: SourceMap, sourcesRoot?: string): SourceMap { if (!sourcesRoot) { return sourceMap; } diff --git a/packager/src/node-haste/Module.js b/packager/src/node-haste/Module.js index 2a5a7957dd9..793fc2ea3c3 100644 --- a/packager/src/node-haste/Module.js +++ b/packager/src/node-haste/Module.js @@ -24,7 +24,7 @@ const {join: joinPath, relative: relativePath, extname} = require('path'); import type {TransformedCode, Options as TransformOptions} from '../JSTransformer/worker/worker'; import type {GlobalTransformCache} from '../lib/GlobalTransformCache'; -import type {SourceMap} from '../lib/SourceMap'; +import type {MappingsMap} from '../lib/SourceMap'; import type {GetTransformCacheKey} from '../lib/TransformCache'; import type {ReadTransformProps} from '../lib/TransformCache'; import type {Reporter} from '../lib/reporting'; @@ -35,7 +35,7 @@ export type ReadResult = { +code: string, +dependencies: Array, +dependencyOffsets?: ?Array, - +map?: ?SourceMap, + +map?: ?MappingsMap, +source: string, };