Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion tools/cli/src/helpers/errorBehavior.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Err, Ok, Result, ResultErr } from '@backtrace/sourcemap-tools';
import { Err, LogLevel, Ok, Result, ResultErr } from '@backtrace/sourcemap-tools';

export const ErrorBehaviors = {
exit: 'exit',
Expand Down Expand Up @@ -52,3 +52,17 @@ export function filterBehaviorSkippedElements<T>(asset: Array<T | BehaviorSkippe
(a) => !(typeof a === 'object' && !!a && 'reason' in a && a.reason instanceof ResultErr),
) as T[];
}

export function isFatal(behavior: ErrorBehavior) {
return behavior === 'exit';
}

export function shouldLog(behavior: ErrorBehavior): behavior is LogLevel {
switch (behavior) {
case 'exit':
case 'skip':
return false;
default:
return true;
}
}
33 changes: 22 additions & 11 deletions tools/cli/src/helpers/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,30 @@ import { Asset, log, LogLevel, ProcessAssetResult } from '@backtrace/sourcemap-t
import { CliLogger } from '../logger';
import { SourceAndSourceMapPaths } from '../models/Asset';

export function logAsset(logger: CliLogger, level: LogLevel) {
const logFn = log(logger, level);
export function createAssetLogger(
logger: CliLogger,
): (level: LogLevel) => <T extends Asset | ProcessAssetResult>(message: string | ((t: T) => string)) => (asset: T) => T;
export function createAssetLogger(
logger: CliLogger,
level: LogLevel,
): <T extends Asset | ProcessAssetResult>(message: string | ((t: T) => string)) => (asset: T) => T;
export function createAssetLogger(logger: CliLogger, level?: LogLevel) {
function logAsset(level: LogLevel) {
const logFn = log(logger, level);

return function logAsset<T extends Asset | ProcessAssetResult>(message: string | ((t: T) => string)) {
return function logAsset(asset: T) {
return logFn<T>(
(t) =>
`${'name' in t ? t.name : t.asset.name}: ${
typeof message === 'function' ? message(asset) : message
}`,
)(asset);
return function logAsset<T extends Asset | ProcessAssetResult>(message: string | ((t: T) => string)) {
return function logAsset(asset: T) {
return logFn<T>(
(t) =>
`${'name' in t ? t.name : t.asset.name}: ${
typeof message === 'function' ? message(asset) : message
}`,
)(asset);
};
};
};
}

return level ? logAsset(level) : logAsset;
}

export const logAssets =
Expand Down
87 changes: 71 additions & 16 deletions tools/cli/src/sourcemaps/add-sources.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
AddSourcesResult,
Asset,
AssetWithContent,
DebugIdGenerator,
Expand All @@ -18,16 +19,25 @@ import {
pipe,
R,
RawSourceMap,
Result,
ResultPromise,
SourceProcessor,
} from '@backtrace/sourcemap-tools';
import path from 'path';
import { GlobalOptions } from '..';
import { Command, CommandContext } from '../commands/Command';
import { readSourceMapFromPathOrFromSource, toAsset, writeAsset } from '../helpers/common';
import { ErrorBehaviors, filterBehaviorSkippedElements, getErrorBehavior, handleError } from '../helpers/errorBehavior';
import {
ErrorBehavior,
ErrorBehaviors,
filterBehaviorSkippedElements,
getErrorBehavior,
handleError,
isFatal,
shouldLog,
} from '../helpers/errorBehavior';
import { buildIncludeExclude, file2Or1FromTuple, findTuples } from '../helpers/find';
import { logAsset } from '../helpers/logs';
import { createAssetLogger } from '../helpers/logs';
import { normalizePaths, relativePaths } from '../helpers/normalizePaths';
import { CliLogger } from '../logger';
import { findConfig, loadOptionsForCommand } from '../options/loadOptions';
Expand All @@ -41,6 +51,11 @@ export interface AddSourcesOptions extends GlobalOptions {
readonly skipFailing: boolean;
readonly 'pass-with-no-files': boolean;
readonly 'asset-error-behavior': string;
readonly 'source-error-behavior': string;
}

interface AssetAddSourcesResult extends AssetWithContent<RawSourceMap> {
readonly result: AddSourcesResult;
}

export const addSourcesCmd = new Command<AddSourcesOptions>({
Expand Down Expand Up @@ -86,6 +101,13 @@ export const addSourcesCmd = new Command<AddSourcesOptions>({
type: String,
description: `What to do when an asset fails. Can be one of: ${Object.keys(ErrorBehaviors).join(', ')}.`,
})
.option({
name: 'source-error-behavior',
type: String,
description: `What to do when reading sourcepath fails. Can be one of: ${Object.keys(ErrorBehaviors).join(
', ',
)}.`,
})
.option({
name: 'pass-with-no-files',
type: Boolean,
Expand Down Expand Up @@ -123,8 +145,9 @@ export async function addSourcesToSourcemaps({ opts, logger, getHelpMessage }: C

const logDebug = log(logger, 'debug');
const logTrace = log(logger, 'trace');
const logDebugAsset = logAsset(logger, 'debug');
const logTraceAsset = logAsset(logger, 'trace');
const logAsset = createAssetLogger(logger);
const logDebugAsset = logAsset('debug');
const logTraceAsset = logAsset('trace');

const assetErrorBehaviorResult = getErrorBehavior(opts['asset-error-behavior'] ?? 'exit');
if (assetErrorBehaviorResult.isErr()) {
Expand All @@ -134,10 +157,46 @@ export async function addSourcesToSourcemaps({ opts, logger, getHelpMessage }: C

const assetErrorBehavior = assetErrorBehaviorResult.data;

const sourceErrorBehaviorResult = getErrorBehavior(opts['source-error-behavior'] ?? 'warn');
if (sourceErrorBehaviorResult.isErr()) {
logger.info(getHelpMessage());
return sourceErrorBehaviorResult;
}

const sourceErrorBehavior = sourceErrorBehaviorResult.data;

const handleFailedAsset = handleError(assetErrorBehavior);

const logAssetBehaviorError = (asset: Asset) => (err: string, level: LogLevel) =>
logAsset(logger, level)(err)(asset);
createAssetLogger(logger, level)(err)(asset);

const processAssetResult =
(behavior: ErrorBehavior) =>
(result: AssetAddSourcesResult): Result<AssetAddSourcesResult, string> => {
const { succeeded, skipped, failed } = result.result;
if (failed.length) {
if (isFatal(behavior)) {
return Err(
`failed to find source for ${failed[0]}` +
(failed.length > 1 ? ` (and ${failed.length} more)` : ''),
);
} else if (shouldLog(behavior)) {
for (const path of failed) {
logAsset(behavior)(`failed to find source for ${path}`)(result);
}
}
}

for (const path of skipped) {
logDebugAsset(`skipped source for ${path}`)(result);
}

for (const path of succeeded) {
logTraceAsset(`added source for ${path}`)(result);
}

return Ok(result);
};

const addSourcesCommand = (asset: Asset) =>
pipe(
Expand All @@ -147,6 +206,7 @@ export async function addSourcesToSourcemaps({ opts, logger, getHelpMessage }: C
R.map(logDebugAsset('read sourcemap')),
R.map(logTraceAsset('adding source')),
R.map(addSourceToSourceMap(opts.force ?? false)),
R.map(processAssetResult(sourceErrorBehavior)),
R.map(logDebugAsset('source added')),
R.map(
opts['dry-run']
Expand Down Expand Up @@ -192,19 +252,14 @@ export async function addSourcesToSourcemaps({ opts, logger, getHelpMessage }: C
export function addSourceToSourceMap(force: boolean) {
const sourceProcessor = new SourceProcessor(new DebugIdGenerator());

const hasSources = (asset: AssetWithContent<RawSourceMap>): asset is AssetWithContent<RawSourceMap> =>
sourceProcessor.doesSourceMapHaveSources(asset.content);

return async function addSourceToSourceMap(
asset: AssetWithContent<RawSourceMap>,
): ResultPromise<AssetWithContent<RawSourceMap>, string> {
return !hasSources(asset) || force
? pipe(
asset,
(asset) => sourceProcessor.addSourcesToSourceMap(asset.content, asset.path),
R.map((content) => ({ ...asset, content } as AssetWithContent<RawSourceMap>)),
)
: Ok(asset);
): ResultPromise<AssetAddSourcesResult, string> {
return pipe(
asset,
(asset) => sourceProcessor.addSourcesToSourceMap(asset.content, asset.path, force),
R.map((result) => ({ ...asset, content: result.sourceMap, result })),
);
};
}

Expand Down
4 changes: 2 additions & 2 deletions tools/cli/src/sourcemaps/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { Command, CommandContext } from '../commands/Command';
import { readSourceAndSourceMap, toSourceAndSourceMapPaths, writeSourceAndSourceMap } from '../helpers/common';
import { ErrorBehaviors, filterBehaviorSkippedElements, getErrorBehavior, handleError } from '../helpers/errorBehavior';
import { buildIncludeExclude, findTuples } from '../helpers/find';
import { logAsset, logAssets } from '../helpers/logs';
import { createAssetLogger, logAssets } from '../helpers/logs';
import { normalizePaths, relativePaths } from '../helpers/normalizePaths';
import { CliLogger } from '../logger';
import { SourceAndSourceMapPaths } from '../models/Asset';
Expand Down Expand Up @@ -135,7 +135,7 @@ export async function processSources({ opts, logger, getHelpMessage }: CommandCo
const handleFailedAsset = handleError(assetErrorBehavior);

const logAssetBehaviorError = (asset: Asset) => (err: string, level: LogLevel) =>
logAsset(logger, level)(err)(asset);
createAssetLogger(logger, level)(err)(asset);

const processAssetCommand = (asset: SourceAndSourceMapPaths) =>
pipe(
Expand Down
8 changes: 4 additions & 4 deletions tools/cli/src/sourcemaps/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import {
} from '../helpers/common';
import { ErrorBehaviors, filterBehaviorSkippedElements, getErrorBehavior, handleError } from '../helpers/errorBehavior';
import { buildIncludeExclude, findTuples } from '../helpers/find';
import { logAsset, logAssets } from '../helpers/logs';
import { createAssetLogger, logAssets } from '../helpers/logs';
import { normalizePaths, relativePaths } from '../helpers/normalizePaths';
import { SourceAndSourceMapPaths } from '../models/Asset';
import { findConfig, joinOptions, loadOptions } from '../options/loadOptions';
Expand Down Expand Up @@ -225,8 +225,8 @@ export async function runSourcemapCommands({ opts, logger, getHelpMessage }: Com
const logInfo = log(logger, 'info');
const logDebug = log(logger, 'debug');
const logTrace = log(logger, 'trace');
const logDebugAsset = logAsset(logger, 'trace');
const logTraceAsset = logAsset(logger, 'trace');
const logDebugAsset = createAssetLogger(logger, 'trace');
const logTraceAsset = createAssetLogger(logger, 'trace');
const logDebugAssets = logAssets(logger, 'debug');
const logTraceAssets = logAssets(logger, 'trace');

Expand All @@ -241,7 +241,7 @@ export async function runSourcemapCommands({ opts, logger, getHelpMessage }: Com
const handleFailedAsset = handleError(assetErrorBehavior);

const logAssetBehaviorError = (asset: Asset) => (err: string, level: LogLevel) =>
logAsset(logger, level)(err)(asset);
createAssetLogger(logger, level)(err)(asset);

const readAssetCommand = (asset: SourceAndSourceMapPaths) =>
pipe(
Expand Down
8 changes: 4 additions & 4 deletions tools/cli/src/sourcemaps/upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { Command, CommandContext } from '../commands/Command';
import { isAssetProcessed, readSourceMapFromPathOrFromSource, toAsset, uniqueBy, validateUrl } from '../helpers/common';
import { ErrorBehaviors, filterBehaviorSkippedElements, getErrorBehavior, handleError } from '../helpers/errorBehavior';
import { buildIncludeExclude, file2Or1FromTuple, findTuples } from '../helpers/find';
import { logAsset } from '../helpers/logs';
import { createAssetLogger } from '../helpers/logs';
import { normalizePaths, relativePaths } from '../helpers/normalizePaths';
import { CliLogger } from '../logger';
import { findConfig, loadOptionsForCommand } from '../options/loadOptions';
Expand Down Expand Up @@ -196,8 +196,8 @@ export async function uploadSourcemaps({ opts, logger, getHelpMessage }: Command

const logDebug = log(logger, 'debug');
const logTrace = log(logger, 'trace');
const logDebugAsset = logAsset(logger, 'debug');
const logTraceAsset = logAsset(logger, 'trace');
const logDebugAsset = createAssetLogger(logger, 'debug');
const logTraceAsset = createAssetLogger(logger, 'trace');

const assetErrorBehaviorResult = getErrorBehavior(opts['asset-error-behavior'] ?? 'exit');
if (assetErrorBehaviorResult.isErr()) {
Expand All @@ -210,7 +210,7 @@ export async function uploadSourcemaps({ opts, logger, getHelpMessage }: Command
const handleFailedAsset = handleError(assetErrorBehavior);

const logAssetBehaviorError = (asset: Asset) => (err: string, level: LogLevel) =>
logAsset(logger, level)(err)(asset);
createAssetLogger(logger, level)(err)(asset);

const isAssetProcessedCommand = (asset: AssetWithContent<RawSourceMap>) =>
pipe(
Expand Down
Loading