Skip to content

Commit

Permalink
feat: accept babelConfig option making ts possible
Browse files Browse the repository at this point in the history
closes #1
  • Loading branch information
elevatebart committed Jul 11, 2021
1 parent 52d4863 commit a0c7aa7
Showing 1 changed file with 43 additions and 22 deletions.
65 changes: 43 additions & 22 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Plugin, ServerHook, TransformResult } from 'vite';
import type { TransformHook, TransformPluginContext } from 'rollup';
import { transformSync } from '@babel/core';
import type { SourceMap, TransformHook, TransformPluginContext } from 'rollup';
import { transformAsync, TransformOptions } from '@babel/core';
import BabelPluginIstanbul from 'babel-plugin-istanbul';
import * as TestExclude from 'test-exclude';

Expand All @@ -10,6 +10,7 @@ interface IstanbulPluginOptions {
extension?: string|string[];
requireEnv?: boolean;
cypress?: boolean;
babelConfig?: TransformOptions;
}

declare global {
Expand Down Expand Up @@ -42,31 +43,40 @@ function createConfigureServer(): ServerHook {
};
}

function transformCode(this: TransformPluginContext, srcCode: string, id: string, opts: IstanbulPluginOptions): TransformResult {
const plugins = [[ BabelPluginIstanbul, opts ]];
const cwd = process.cwd();
async function instrumentCode(this: TransformPluginContext, srcCode: string, id: string, opts: IstanbulPluginOptions): Promise<TransformResult> {
opts.babelConfig = opts.babelConfig || {}
opts.babelConfig.plugins = opts.babelConfig.plugins || []
opts.babelConfig.parserOpts = opts.babelConfig.parserOpts || {}

const { code, map } = transformSync(srcCode, {
plugins, cwd,
const cwd = process.cwd();
const babelConfig: TransformOptions = {
...opts.babelConfig,
plugins: [...opts.babelConfig.plugins, [ BabelPluginIstanbul, opts ]],
cwd,
filename: id,
ast: false,
sourceMaps: true,
comments: true,
compact: true,
compact: false,
babelrc: false,
configFile: false,
parserOpts: {
...opts.babelConfig.parserOpts,
allowReturnOutsideFunction: true,
sourceType: 'module',
},
// Only keep primitive properties
inputSourceMap: JSON.parse(JSON.stringify(this.getCombinedSourcemap())),
});
inputSourceMap: this.getCombinedSourcemap(),
}

const { code, map } = await transformAsync(srcCode, babelConfig);

// Required to cast to correct mapping value
return { code, map: JSON.parse(JSON.stringify(map)) };
return { code, map: map as SourceMap };
}

const scriptRE = /<script([^>]*)>/g

function createTransform(opts: IstanbulPluginOptions = {}): TransformHook {
const exclude = new TestExclude({
cwd: process.cwd(),
Expand All @@ -76,37 +86,48 @@ function createTransform(opts: IstanbulPluginOptions = {}): TransformHook {
excludeNodeModules: true,
});

return function (srcCode: string, id: string) {
return async function (this: TransformPluginContext, srcCode: string, id: string): Promise<{code:string, map: string}> {
if (process.env.NODE_ENV == 'production' || id.startsWith('/@modules/')) {
// do not transform if this is a dep
// do not transform for production builds
return;
}

if (exclude.shouldInstrument(id)) {
if (!id.endsWith('.vue')) {
return transformCode.call(this, srcCode, id, opts);
// is the vue component has already been transformed,
// it can only be sliced
if (!id.endsWith('.vue') || srcCode.trim().slice(0, 1) !== "<") {
return instrumentCode.call(this, srcCode, id, opts);
}

// Vue files are special, it requires a hack to fix the source mappings
// We take the source code from within the <script> tag and instrument this
// Then we pad the lines to get the correct line numbers for the mappings
let startIndex = srcCode.indexOf('<script>');
const openScriptTagObject = scriptRE.exec(srcCode) || { index: -1};
const endIndex = srcCode.indexOf('</script>');

if (startIndex == -1 || endIndex == -1) {
if (!openScriptTagObject || endIndex == -1) {
// ignore this vue file, doesn't contain any javascript
return;
}

const startIndex = openScriptTagObject.index
const openScriptTag = openScriptTagObject[0]

const lines = srcCode.slice(0, endIndex).match(/\n/g)?.length ?? 0;
const startOffset = '<script>'.length;
const numberOfLinesBeforeScript = srcCode.slice(0, endIndex).match(/\n/g)?.length ?? 0;
const startOffset = openScriptTag.length;

const scriptCode = '\n'.repeat(numberOfLinesBeforeScript) + srcCode.slice(startIndex + startOffset, endIndex);

srcCode = '\n'.repeat(lines) + srcCode.slice(startIndex + startOffset, endIndex);
const res = await instrumentCode.call(this, scriptCode, id, opts);

const res = transformCode.call(this, srcCode, id, opts);
// if </script> is anywhere in the script block, even in a string,
// the parser errors
const resCodeSanatized = res.code.replace(/<\/script>/g, "<\\/script>")

res.code = `${srcCode.slice(0, startIndex + startOffset)}\n${res.code}\n${srcCode.slice(endIndex)}`;
console.log(resCodeSanatized)

res.code = `${srcCode.slice(0, startIndex + startOffset)}\n${resCodeSanatized}\n${srcCode.slice(endIndex)}`;
return res;
}
};
Expand Down

0 comments on commit a0c7aa7

Please sign in to comment.