Skip to content
This repository has been archived by the owner on Aug 4, 2021. It is now read-only.

Support custom typescript plugins #100

Closed
wants to merge 1 commit into from
Closed
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
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,16 @@
"object-assign": "^4.0.1",
"rollup-pluginutils": "^1.3.1",
"tippex": "^2.1.1",
"typescript": "^1.8.9"
"typescript": "^2.6.2"
},
"devDependencies": {
"buble": "^0.13.1",
"eslint": "^2.13.1",
"mocha": "^3.0.0",
"rimraf": "^2.5.4",
"rollup": "^0.49.3",
"rollup-plugin-buble": "^0.13.0"
"rollup-plugin-buble": "^0.13.0",
"ts-transform-safely": "0.0.4"
},
"repository": {
"type": "git",
Expand Down
13 changes: 11 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ export default function typescript ( options ) {
adjustCompilerOptions( typescript, tsconfig );
adjustCompilerOptions( typescript, options );

const transformers = typeof options.getCustomTransformers === 'function' ? options.getCustomTransformers() : null;
delete options.getCustomTransformers;

// Merge all options.
options = assign( tsconfig, getDefaultOptions(), options );

Expand Down Expand Up @@ -108,11 +111,17 @@ export default function typescript ( options ) {
transform ( code, id ) {
if ( !filter( id ) ) return null;

const transformed = typescript.transpileModule( fixExportClass( code, id ), {
const opts = {
fileName: id,
reportDiagnostics: true,
compilerOptions
});
};

if (transformers) {
opts.transformers = transformers;
}

const transformed = typescript.transpileModule( fixExportClass( code, id ), opts );

// All errors except `Cannot compile modules into 'es6' when targeting 'ES5' or lower.`
const diagnostics = transformed.diagnostics ?
Expand Down
17 changes: 13 additions & 4 deletions src/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,19 @@ export function adjustCompilerOptions ( typescript, options ) {
// See: https://github.com/rollup/rollup-plugin-typescript/issues/45
delete options.declaration;

const requiredVersions = {
strictNullChecks: '1.9.0',
getCustomTransformers: '2.3.0'
};

const tsVersion = typescript.version.split('-')[0];
if ( 'strictNullChecks' in options && compareVersions( tsVersion, '1.9.0' ) < 0 ) {
delete options.strictNullChecks;

console.warn( `rollup-plugin-typescript: 'strictNullChecks' is not supported; disabling it` );
}
Object.keys(requiredVersions).forEach((key) => {
const version = requiredVersions[key];
if (key in options && compareVersions( tsVersion, version ) < 0) {
delete options[key];

console.warn( `rollup-plugin-typescript: '${key}' is not supported with TypeScript < v${version}; disabling it` );
}
});
}
17 changes: 17 additions & 0 deletions test/sample/transformers/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export function getName(people, index) {
return get(people, [index, 'name'], 'Unknown');
}

export function getName_transformed(people, index) {
return people && people[index] && people[index]['name'] || 'Unknown';
}

export function getNameUndefined(people, index) {
const name = get(people, [index, 'name'], 'Unknown');
return name === 'Unknown' ? undefined : name;
}

export function getNameUndefined_transformed(people, index) {
const name = people && people[index] && people[index]['name'] || 'Unknown';
return name === 'Unknown' ? void 0 : name;
}
49 changes: 49 additions & 0 deletions test/sample/transformers/transformers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const ts = require('typescript');

const guardedAccess = (/* options */) => (context) => (sourceFile) => {
const visitor = (node) => {
if (ts.isCallExpression(node) &&
node.expression.getText(sourceFile) === 'get') {
const [obj, path, defaultValue] = node.arguments;
// check to make sure it is the expected argument types
if (ts.isArrayLiteralExpression(path)) {
// return a binary expression like a && a.b && a.b.c || defaultValue
return ts.createBinary(
// the gaurded access
path.elements.reduce((prev, elem) => [
...prev,
ts.createElementAccess(prev[prev.length - 1], ts.visitNode(elem, visitor))
], [obj]).reduce((prev, elem) => ts.createBinary(
prev,
ts.SyntaxKind.AmpersandAmpersandToken,
elem
)),
// the || operator
ts.SyntaxKind.BarBarToken,
defaultValue
);
}
}
// otherwise continue visiting all the nodes
return ts.visitEachChild(node, visitor, context);
};

return ts.visitNode(sourceFile, visitor);
};

const void0 = (/* options */) => (context) => (sourceFile) => {
const visitor = (node) => {
if (ts.isIdentifier(node) &&
node.getText(sourceFile) === 'undefined') {
// return `void 0` instead
return ts.createVoidZero();
}
// otherwise continue visiting all the nodes
return ts.visitEachChild(node, visitor, context);
};

return ts.visitNode(sourceFile, visitor);
};

exports.guardedAccess = guardedAccess;
exports.void0 = void0;
1 change: 1 addition & 0 deletions test/sample/transformers/ts-loader-compat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
safely(a.b);
138 changes: 129 additions & 9 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ function bundle ( main, options ) {
});
}

function getNextWarning ( callback ) {
const warn = console.warn;
console.warn = (message) => {
console.warn = warn;
callback(message);
};
}

describe( 'rollup-plugin-typescript', function () {
this.timeout( 5000 );

Expand All @@ -38,7 +46,9 @@ describe( 'rollup-plugin-typescript', function () {
});

it( 'handles async functions', async () => {
const b = await bundle( 'sample/async/main.ts' );
const b = await bundle( 'sample/async/main.ts', {
target: 'es2015'
});
const wait = await evaluate(b);

return wait(3);
Expand All @@ -59,17 +69,17 @@ describe( 'rollup-plugin-typescript', function () {
const b = await bundle( 'sample/export-class-fix/main.ts' );
const { code } = await b.generate({ format: 'es' });

assert.equal( code.indexOf( 'class' ), -1, code );
assert.ok( code.indexOf( 'var A = (function' ) !== -1, code );
assert.ok( code.indexOf( 'var B = (function' ) !== -1, code );
assert.ok( code.indexOf( 'export { A, B };' ) !== -1, code );
assert.equal( code.indexOf( 'class A' ), -1, code );
assert.notEqual( code.indexOf( 'var A = /** @class */ (function' ), -1, code );
assert.notEqual( code.indexOf( 'var B = /** @class */ (function' ), -1, code );
assert.notEqual( code.indexOf( 'export { A, B };' ), -1, code );
});

it( 'transpiles ES6 features to ES5 with source maps', async () => {
const b = await bundle( 'sample/import-class/main.ts' );
const { code } = await b.generate({ format: 'es' });

assert.equal( code.indexOf( 'class' ), -1, code );
assert.equal( code.indexOf( 'class A' ), -1, code );
assert.equal( code.indexOf( '...' ), -1, code );
assert.equal( code.indexOf( '=>' ), -1, code );
});
Expand Down Expand Up @@ -145,9 +155,9 @@ describe( 'rollup-plugin-typescript', function () {
it( 'is disabled with a warning < 1.9.0', async () => {
let warning = '';

console.warn = function (msg) {
warning = msg;
};
getNextWarning((message) => {
warning = message;
});

await rollup.rollup({
input: 'sample/overriding-typescript/main.ts',
Expand Down Expand Up @@ -217,6 +227,116 @@ describe( 'rollup-plugin-typescript', function () {

assert.ok( map.sources.every( source => source.indexOf( 'typescript-helpers' ) === -1) );
});

describe( 'transformers', () => {
it( 'is enabled for versions >= 2.3.0', async () => {
await bundle( 'sample/overriding-typescript/main.ts', {
tsconfig: false,
getCustomTransformers: () => ({}),

typescript: fakeTypescript({
version: '2.3.0-fake',
transpileModule ( code, options ) {
assert.ok( options.transformers,
'transformers should be passed in' );

return {
outputText: '',
diagnostics: [],
sourceMapText: JSON.stringify({ mappings: '' })
};
}
})
});
});

it( 'is disabled with a warning < 2.3.0', async () => {
let warning = '';

getNextWarning((message) => {
warning = message;
});

await rollup.rollup({
input: 'sample/overriding-typescript/main.ts',
plugins: [
typescript({
tsconfig: false,
getCustomTransformers: () => ({}),

typescript: fakeTypescript({
version: '2.2.0-fake'
})
})
]
});

assert.notEqual( warning.indexOf( "'getCustomTransformers' is not supported" ), -1 );
});

it( 'applies one correctly', async () => {
const transformers = require( './sample/transformers/transformers' );

const b = await bundle( 'sample/transformers/main.ts', {
getCustomTransformers: () => ({
before: [
transformers.guardedAccess()
]
})
});
const { code } = await b.generate({ format: 'es' });

assert.equal(
code.match(/function getName\(people, index\) {([\s\S]*?)}/)[1],
code.match(/function getName_transformed\(people, index\) {([\s\S]*?)}/)[1],
'output transformed function body should be identical to expected'
);
});

it( 'applies multiple correctly', async () => {
const transformers = require( './sample/transformers/transformers' );

const b = await bundle( 'sample/transformers/main.ts', {
getCustomTransformers: () => ({
before: [
transformers.guardedAccess(),
transformers.void0()
]
})
});
const { code } = await b.generate({ format: 'es' });

assert.equal(
code.match(/function getName\(people, index\) {([\s\S]*?)}/)[1],
code.match(/function getName_transformed\(people, index\) {([\s\S]*?)}/)[1],
'output transformed getName function body should equal to expectation'
);

assert.equal(
code.match(/function getNameUndefined\(people, index\) {([\s\S]*?)}/)[1],
code.match(/function getNameUndefined_transformed\(people, index\) {([\s\S]*?)}/)[1],
'output transformed getNameUndefined function body should equal to expectation'
);
});

it( 'supports format compatible with webpack ts-loader', async () => {
const transform = require('ts-transform-safely').transform;

const b = await bundle( 'sample/transformers/ts-loader-compat.ts', {
getCustomTransformers: () => ({
before: [
transform()
]
})
});

const { code } = await b.generate({ format: 'es' });
assert.equal(
code,
`a == null ? void 0 : a.b;\n`
);
});
});
});

function fakeTypescript ( custom ) {
Expand Down