diff --git a/.gitignore b/.gitignore index 6897440..ae1044b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ node_modules -dist .DS_Store coverage/ *.log diff --git a/dist/cli.d.ts b/dist/cli.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/dist/cli.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/cli.js b/dist/cli.js new file mode 100644 index 0000000..23a363c --- /dev/null +++ b/dist/cli.js @@ -0,0 +1,117 @@ +#!/usr/bin/env node +"use strict"; +var __values = (this && this.__values) || function (o) { + var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; + if (m) return m.call(o); + return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var program = require("commander"); +var glob = require("glob"); +var fs = require("fs"); +var path = require("path"); +var _1 = require("."); +function resolveGlobs(globPatterns) { + var files = []; + function addFile(file) { + file = path.resolve(file); + if (files.indexOf(file) === -1) { + files.push(file); + } + } + globPatterns.forEach(function (pattern) { + if (/[{}*?+\[\]]/.test(pattern)) { + // Smells like globs + glob.sync(pattern, {}).forEach(function (file) { + addFile(file); + }); + } + else { + addFile(pattern); + } + }); + return files; +} +program + .version('1.0.0') + .option('--arrow-parens ', 'Include parentheses around a sole arrow function parameter.', 'avoid') + .option('--no-bracket-spacing', 'Do not print spaces between brackets.', false) + .option('--jsx-bracket-same-line', 'Put > on the last line instead of at a new line.', false) + .option('--print-width ', 'The line length where Prettier will try wrap.', 80) + .option('--prose-wrap How to wrap prose. (markdown)', 'preserve') + .option('--no-semi', 'Do not print semicolons, except at the beginning of lines which may need them', false) + .option('--single-quote', 'Use single quotes instead of double quotes.', false) + .option('--tab-width ', 'Number of spaces per indentation level.', 2) + .option('--trailing-comma ', 'Print trailing commas wherever possible when multi-line.', 'none') + .option('--use-tabs', 'Indent with tabs instead of spaces.', false) + .option('--ignore-prettier-errors', 'Ignore (but warn about) errors in Prettier', false) + .option('--keep-original-files', 'Keep original files', false) + .option('--keep-temporary-files', 'Keep temporary files', false) + .usage('[options] ') + .command('* [glob/filename...]') + .action(function (globPatterns) { + var prettierOptions = { + arrowParens: program.arrowParens, + bracketSpacing: !program.noBracketSpacing, + jsxBracketSameLine: !!program.jsxBracketSameLine, + printWidth: parseInt(program.printWidth, 10), + proseWrap: program.proseWrap, + semi: !program.noSemi, + singleQuote: !!program.singleQuote, + tabWidth: parseInt(program.tabWidth, 10), + trailingComma: program.trailingComma, + useTabs: !!program.useTabs, + }; + var compilationOptions = { + ignorePrettierErrors: !!program.ignorePrettierErrors, + }; + var files = resolveGlobs(globPatterns); + if (!files.length) { + throw new Error('Nothing to do. You must provide file names or glob patterns to transform.'); + } + var errors = false; + try { + for (var files_1 = __values(files), files_1_1 = files_1.next(); !files_1_1.done; files_1_1 = files_1.next()) { + var filePath = files_1_1.value; + console.log("Transforming " + filePath + "..."); + var newPath = filePath.replace(/\.jsx?$/, '.tsx'); + var temporaryPath = filePath.replace(/\.jsx?$/, "_js2ts_" + +new Date() + ".tsx"); + try { + fs.copyFileSync(filePath, temporaryPath); + var result = _1.run(temporaryPath, prettierOptions, compilationOptions); + fs.writeFileSync(newPath, result); + if (!program.keepOriginalFiles) { + fs.unlinkSync(filePath); + } + } + catch (error) { + console.warn("Failed to convert " + filePath); + console.warn(error); + errors = true; + } + if (!program.keepTemporaryFiles) { + if (fs.existsSync(temporaryPath)) { + fs.unlinkSync(temporaryPath); + } + } + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (files_1_1 && !files_1_1.done && (_a = files_1.return)) _a.call(files_1); + } + finally { if (e_1) throw e_1.error; } + } + if (errors) { + process.exit(1); + } + var e_1, _a; +}); +program.parse(process.argv); +//# sourceMappingURL=cli.js.map \ No newline at end of file diff --git a/dist/cli.js.map b/dist/cli.js.map new file mode 100644 index 0000000..24c4320 --- /dev/null +++ b/dist/cli.js.map @@ -0,0 +1 @@ +{"version":3,"file":"cli.js","sourceRoot":"/Users/ethans/Documents/workspace/src/","sources":["cli.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAEA,mCAAqC;AACrC,2BAA6B;AAC7B,uBAAyB;AACzB,2BAA6B;AAG7B,sBAAwB;AAGxB,sBAAsB,YAAsB;IACxC,IAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,iBAAiB,IAAY;QACzB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1B,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE;YAC5B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SACpB;IACL,CAAC;IACD,YAAY,CAAC,OAAO,CAAC,UAAA,OAAO;QACxB,IAAI,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;YAC7B,oBAAoB;YACpB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,UAAA,IAAI;gBAC/B,OAAO,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC,CAAC,CAAC;SACN;aAAM;YACH,OAAO,CAAC,OAAO,CAAC,CAAC;SACpB;IACL,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,OAAO;KACF,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,+BAA+B,EAAE,6DAA6D,EAAE,OAAO,CAAC;KAC/G,MAAM,CAAC,sBAAsB,EAAE,uCAAuC,EAAE,KAAK,CAAC;KAC9E,MAAM,CAAC,yBAAyB,EAAE,kDAAkD,EAAE,KAAK,CAAC;KAC5F,MAAM,CAAC,qBAAqB,EAAE,+CAA+C,EAAE,EAAE,CAAC;KAClF,MAAM,CAAC,oEAAoE,EAAE,UAAU,CAAC;KACxF,MAAM,CAAC,WAAW,EAAE,+EAA+E,EAAE,KAAK,CAAC;KAC3G,MAAM,CAAC,gBAAgB,EAAE,6CAA6C,EAAE,KAAK,CAAC;KAC9E,MAAM,CAAC,mBAAmB,EAAE,yCAAyC,EAAE,CAAC,CAAC;KACzE,MAAM,CAAC,iCAAiC,EAAE,0DAA0D,EAAE,MAAM,CAAC;KAC7G,MAAM,CAAC,YAAY,EAAE,qCAAqC,EAAE,KAAK,CAAC;KAClE,MAAM,CAAC,0BAA0B,EAAE,4CAA4C,EAAE,KAAK,CAAC;KACvF,MAAM,CAAC,uBAAuB,EAAE,qBAAqB,EAAE,KAAK,CAAC;KAC7D,MAAM,CAAC,wBAAwB,EAAE,sBAAsB,EAAE,KAAK,CAAC;KAC/D,KAAK,CAAC,8BAA8B,CAAC;KACrC,OAAO,CAAC,sBAAsB,CAAC;KAC/B,MAAM,CAAC,UAAC,YAAsB;IAC3B,IAAM,eAAe,GAAqB;QACtC,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,cAAc,EAAE,CAAC,OAAO,CAAC,gBAAgB;QACzC,kBAAkB,EAAE,CAAC,CAAC,OAAO,CAAC,kBAAkB;QAChD,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;QAC5C,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM;QACrB,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW;QAClC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;QACxC,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO;KAC7B,CAAC;IACF,IAAM,kBAAkB,GAAuB;QAC3C,oBAAoB,EAAE,CAAC,CAAC,OAAO,CAAC,oBAAoB;KACvD,CAAC;IACF,IAAM,KAAK,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;QACf,MAAM,IAAI,KAAK,CAAC,2EAA2E,CAAC,CAAC;KAChG;IACD,IAAI,MAAM,GAAG,KAAK,CAAC;;QACnB,KAAuB,IAAA,UAAA,SAAA,KAAK,CAAA,4BAAA;YAAvB,IAAM,QAAQ,kBAAA;YACf,OAAO,CAAC,GAAG,CAAC,kBAAgB,QAAQ,QAAK,CAAC,CAAC;YAC3C,IAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YACpD,IAAM,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,YAAU,CAAC,IAAI,IAAI,EAAE,SAAM,CAAC,CAAC;YAC/E,IAAI;gBACA,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;gBACzC,IAAM,MAAM,GAAG,MAAG,CAAC,aAAa,EAAE,eAAe,EAAE,kBAAkB,CAAC,CAAC;gBACvE,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gBAClC,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE;oBAC5B,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;iBAC3B;aACJ;YAAC,OAAO,KAAK,EAAE;gBACZ,OAAO,CAAC,IAAI,CAAC,uBAAqB,QAAU,CAAC,CAAC;gBAC9C,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACpB,MAAM,GAAG,IAAI,CAAC;aACjB;YACD,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE;gBAC7B,IAAI,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE;oBAC9B,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;iBAChC;aACJ;SACJ;;;;;;;;;IACD,IAAI,MAAM,EAAE;QACR,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KACnB;;AACL,CAAC,CAAC,CAAC;AAEP,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/compiler.d.ts b/dist/compiler.d.ts new file mode 100644 index 0000000..8e80695 --- /dev/null +++ b/dist/compiler.d.ts @@ -0,0 +1,19 @@ +import * as prettier from 'prettier'; +import { TransformFactoryFactory } from '.'; +export interface CompilationOptions { + ignorePrettierErrors: boolean; +} +declare const DEFAULT_COMPILATION_OPTIONS: CompilationOptions; +export { DEFAULT_COMPILATION_OPTIONS }; +/** + * Compile and return result TypeScript + * @param filePath Path to file to compile + */ +export declare function compile(filePath: string, factoryFactories: TransformFactoryFactory[], incomingPrettierOptions?: prettier.Options, compilationOptions?: CompilationOptions): string; +/** + * Get Prettier options based on style of a JavaScript + * @param filePath Path to source file + * @param source Body of a JavaScript + * @param options Existing prettier option + */ +export declare function getPrettierOptions(filePath: string, source: string, options: prettier.Options): prettier.Options; diff --git a/dist/compiler.js b/dist/compiler.js new file mode 100644 index 0000000..7fc516b --- /dev/null +++ b/dist/compiler.js @@ -0,0 +1,135 @@ +"use strict"; +var __values = (this && this.__values) || function (o) { + var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; + if (m) return m.call(o); + return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var os = require("os"); +var fs = require("fs"); +var ts = require("typescript"); +var chalk_1 = require("chalk"); +var _ = require("lodash"); +var prettier = require("prettier"); +var detectIndent = require("detect-indent"); +var DEFAULT_COMPILATION_OPTIONS = { + ignorePrettierErrors: false, +}; +exports.DEFAULT_COMPILATION_OPTIONS = DEFAULT_COMPILATION_OPTIONS; +/** + * Compile and return result TypeScript + * @param filePath Path to file to compile + */ +function compile(filePath, factoryFactories, incomingPrettierOptions, compilationOptions) { + if (incomingPrettierOptions === void 0) { incomingPrettierOptions = {}; } + if (compilationOptions === void 0) { compilationOptions = DEFAULT_COMPILATION_OPTIONS; } + var compilerOptions = { + target: ts.ScriptTarget.ES2017, + module: ts.ModuleKind.ES2015, + }; + var program = ts.createProgram([filePath], compilerOptions); + // `program.getSourceFiles()` will include those imported files, + // like: `import * as a from './file-a'`. + // We should only transform current file. + var sourceFiles = program.getSourceFiles().filter(function (sf) { return sf.fileName === filePath; }); + var typeChecker = program.getTypeChecker(); + var result = ts.transform(sourceFiles, factoryFactories.map(function (factoryFactory) { return factoryFactory(typeChecker); }, compilerOptions)); + if (result.diagnostics && result.diagnostics.length) { + console.log(chalk_1.default.yellow("\n ======================= Diagnostics for " + filePath + " =======================\n ")); + try { + for (var _a = __values(result.diagnostics), _b = _a.next(); !_b.done; _b = _a.next()) { + var diag = _b.value; + if (diag.file && diag.start) { + var pos = diag.file.getLineAndCharacterOfPosition(diag.start); + console.log("(" + pos.line + ", " + pos.character + ") " + diag.messageText); + } + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (_b && !_b.done && (_c = _a.return)) _c.call(_a); + } + finally { if (e_1) throw e_1.error; } + } + } + var printer = ts.createPrinter(); + // TODO: fix the index 0 access... What if program have multiple source files? + var printed = printer.printNode(ts.EmitHint.SourceFile, result.transformed[0], sourceFiles[0]); + var inputSource = fs.readFileSync(filePath, 'utf-8'); + var prettierOptions = getPrettierOptions(filePath, inputSource, incomingPrettierOptions); + try { + return prettier.format(printed, prettierOptions); + } + catch (prettierError) { + if (compilationOptions.ignorePrettierErrors) { + console.warn("Prettier failed for " + filePath + " (ignorePrettierErrors is on):"); + console.warn(prettierError); + return printed; + } + throw prettierError; + } + var e_1, _c; +} +exports.compile = compile; +/** + * Get Prettier options based on style of a JavaScript + * @param filePath Path to source file + * @param source Body of a JavaScript + * @param options Existing prettier option + */ +function getPrettierOptions(filePath, source, options) { + var resolvedOptions = prettier.resolveConfig.sync(filePath); + if (resolvedOptions) { + _.defaults(resolvedOptions, options); + return resolvedOptions; + } + var _a = detectIndent(source), indentAmount = _a.amount, indentType = _a.type; + var sourceWidth = getCodeWidth(source, 80); + var semi = getUseOfSemi(source); + var quotations = getQuotation(source); + _.defaults(Object.assign({}, options), { + tabWidth: indentAmount, + useTabs: indentType && indentType === 'tab', + printWidth: sourceWidth, + semi: semi, + singleQuote: quotations === 'single', + }); + return options; +} +exports.getPrettierOptions = getPrettierOptions; +/** + * Given body of a source file, return its code width + * @param source + */ +function getCodeWidth(source, defaultWidth) { + return source.split(os.EOL).reduce(function (result, line) { return Math.max(result, line.length); }, defaultWidth); +} +/** + * Detect if a source file is using semicolon + * @todo: use an actual parser. This is not a proper implementation + * @param source + * @return true if code is using semicolons + */ +function getUseOfSemi(source) { + return source.indexOf(';') !== -1; +} +/** + * Detect if a source file is using single quotes or double quotes + * @todo use an actual parser. This is not a proper implementation + * @param source + */ +function getQuotation(source) { + var numberOfSingleQuotes = (source.match(/\'/g) || []).length; + var numberOfDoubleQuotes = (source.match(/\"/g) || []).length; + if (numberOfSingleQuotes > numberOfDoubleQuotes) { + return 'single'; + } + return 'double'; +} +//# sourceMappingURL=compiler.js.map \ No newline at end of file diff --git a/dist/compiler.js.map b/dist/compiler.js.map new file mode 100644 index 0000000..bc3ed5b --- /dev/null +++ b/dist/compiler.js.map @@ -0,0 +1 @@ +{"version":3,"file":"compiler.js","sourceRoot":"/Users/ethans/Documents/workspace/src/","sources":["compiler.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/helpers/build-prop-type-interface.d.ts b/dist/helpers/build-prop-type-interface.d.ts new file mode 100644 index 0000000..327cdc2 --- /dev/null +++ b/dist/helpers/build-prop-type-interface.d.ts @@ -0,0 +1,15 @@ +import * as ts from 'typescript'; +/** + * Build props interface from propTypes object + * @example + * { + * foo: React.PropTypes.string.isRequired + * } + * + * becomes + * { + * foo: string; + * } + * @param objectLiteral + */ +export declare function buildInterfaceFromPropTypeObjectLiteral(objectLiteral: ts.ObjectLiteralExpression): ts.TypeLiteralNode; diff --git a/dist/helpers/build-prop-type-interface.js b/dist/helpers/build-prop-type-interface.js new file mode 100644 index 0000000..489682f --- /dev/null +++ b/dist/helpers/build-prop-type-interface.js @@ -0,0 +1,166 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var ts = require("typescript"); +/** + * Build props interface from propTypes object + * @example + * { + * foo: React.PropTypes.string.isRequired + * } + * + * becomes + * { + * foo: string; + * } + * @param objectLiteral + */ +function buildInterfaceFromPropTypeObjectLiteral(objectLiteral) { + var members = objectLiteral.properties + // We only need to process PropertyAssignment: + // { + // a: 123 // PropertyAssignment + // } + // + // filter out: + // { + // a() {}, // MethodDeclaration + // b, // ShorthandPropertyAssignment + // ...c, // SpreadAssignment + // get d() {}, // AccessorDeclaration + // } + .filter(ts.isPropertyAssignment) + // Ignore children, React types have it + .filter(function (property) { return property.name.getText() !== 'children'; }) + .map(function (propertyAssignment) { + var name = propertyAssignment.name.getText(); + var initializer = propertyAssignment.initializer; + var isRequired = isPropTypeRequired(initializer); + var typeExpression = isRequired + ? // We have guaranteed the type in `isPropTypeRequired()` + initializer.expression + : initializer; + var typeValue = getTypeFromReactPropTypeExpression(typeExpression); + return ts.createPropertySignature([], name, isRequired ? undefined : ts.createToken(ts.SyntaxKind.QuestionToken), typeValue, undefined); + }); + return ts.createTypeLiteralNode(members); +} +exports.buildInterfaceFromPropTypeObjectLiteral = buildInterfaceFromPropTypeObjectLiteral; +/** + * Turns React.PropTypes.* into TypeScript type value + * + * @param node React propTypes value + */ +function getTypeFromReactPropTypeExpression(node) { + var result = null; + if (ts.isPropertyAccessExpression(node)) { + /** + * PropTypes.array, + * PropTypes.bool, + * PropTypes.func, + * PropTypes.number, + * PropTypes.object, + * PropTypes.string, + * PropTypes.symbol, (ignore) + * PropTypes.node, + * PropTypes.element, + * PropTypes.any, + */ + var text = node.getText().replace(/React\.PropTypes\./, ''); + if (/string/.test(text)) { + result = ts.createKeywordTypeNode(ts.SyntaxKind.StringKeyword); + } + else if (/any/.test(text)) { + result = ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword); + } + else if (/array/.test(text)) { + result = ts.createArrayTypeNode(ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)); + } + else if (/bool/.test(text)) { + result = ts.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword); + } + else if (/number/.test(text)) { + result = ts.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword); + } + else if (/object/.test(text)) { + result = ts.createKeywordTypeNode(ts.SyntaxKind.ObjectKeyword); + } + else if (/node/.test(text)) { + result = ts.createTypeReferenceNode('React.ReactNode', []); + } + else if (/element/.test(text)) { + result = ts.createTypeReferenceNode('JSX.Element', []); + } + else if (/func/.test(text)) { + var arrayOfAny = ts.createParameter([], [], ts.createToken(ts.SyntaxKind.DotDotDotToken), 'args', undefined, ts.createArrayTypeNode(ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)), undefined); + result = ts.createFunctionTypeNode([], [arrayOfAny], ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)); + } + } + else if (ts.isCallExpression(node)) { + /** + * PropTypes.instanceOf(), (ignore) + * PropTypes.oneOf(), // only support oneOf([1, 2]), oneOf(['a', 'b']) + * PropTypes.oneOfType(), + * PropTypes.arrayOf(), + * PropTypes.objectOf(), + * PropTypes.shape(), + */ + var text = node.expression.getText(); + if (/oneOf$/.test(text)) { + var argument = node.arguments[0]; + if (ts.isArrayLiteralExpression(argument)) { + if (argument.elements.every(function (elm) { return ts.isStringLiteral(elm) || ts.isNumericLiteral(elm); })) { + result = ts.createUnionTypeNode(argument.elements.map(function (elm) { + return ts.createLiteralTypeNode(elm); + })); + } + } + } + else if (/oneOfType$/.test(text)) { + var argument = node.arguments[0]; + if (ts.isArrayLiteralExpression(argument)) { + result = ts.createUnionOrIntersectionTypeNode(ts.SyntaxKind.UnionType, argument.elements.map(function (elm) { return getTypeFromReactPropTypeExpression(elm); })); + } + } + else if (/arrayOf$/.test(text)) { + var argument = node.arguments[0]; + if (argument) { + result = ts.createArrayTypeNode(getTypeFromReactPropTypeExpression(argument)); + } + } + else if (/objectOf$/.test(text)) { + var argument = node.arguments[0]; + if (argument) { + result = ts.createTypeLiteralNode([ + ts.createIndexSignature(undefined, undefined, [ + ts.createParameter(undefined, undefined, undefined, 'key', undefined, ts.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)), + ], getTypeFromReactPropTypeExpression(argument)), + ]); + } + } + else if (/shape$/.test(text)) { + var argument = node.arguments[0]; + if (ts.isObjectLiteralExpression(argument)) { + return buildInterfaceFromPropTypeObjectLiteral(argument); + } + } + } + /** + * customProp, + * anything others + */ + if (result === null) { + result = ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword); + } + return result; +} +/** + * Decide if node is required + * @param node React propTypes member node + */ +function isPropTypeRequired(node) { + if (!ts.isPropertyAccessExpression(node)) + return false; + var text = node.getText().replace(/React\.PropTypes\./, ''); + return /\.isRequired/.test(text); +} +//# sourceMappingURL=build-prop-type-interface.js.map \ No newline at end of file diff --git a/dist/helpers/build-prop-type-interface.js.map b/dist/helpers/build-prop-type-interface.js.map new file mode 100644 index 0000000..3744e0b --- /dev/null +++ b/dist/helpers/build-prop-type-interface.js.map @@ -0,0 +1 @@ +{"version":3,"file":"build-prop-type-interface.js","sourceRoot":"/Users/ethans/Documents/workspace/src/","sources":["helpers/build-prop-type-interface.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/helpers/index.d.ts b/dist/helpers/index.d.ts new file mode 100644 index 0000000..45d35d5 --- /dev/null +++ b/dist/helpers/index.d.ts @@ -0,0 +1,83 @@ +import * as ts from 'typescript'; +export * from './build-prop-type-interface'; +/** + * If a class declaration a react class? + * @param classDeclaration + * @param typeChecker + */ +export declare function isReactComponent(classDeclaration: ts.ClassDeclaration, typeChecker: ts.TypeChecker): boolean; +/** + * Determine if a ts.HeritageClause is React HeritageClause + * + * @example `extends React.Component<{}, {}>` is a React HeritageClause + * + * @todo: this is lazy. Use the typeChecker instead + * @param clause + */ +export declare function isReactHeritageClause(clause: ts.HeritageClause): boolean; +/** + * Return true if a statement is a React propType assignment statement + * @example + * SomeComponent.propTypes = { foo: React.PropTypes.string }; + * @param statement + */ +export declare function isReactPropTypeAssignmentStatement(statement: ts.Statement): statement is ts.ExpressionStatement; +/** + * Does class member have a "static" member? + * @param classMember + */ +export declare function hasStaticModifier(classMember: ts.ClassElement): boolean; +/** + * Is class member a React "propTypes" member? + * @param classMember + * @param sourceFile + */ +export declare function isPropTypesMember(classMember: ts.ClassElement, sourceFile: ts.SourceFile): boolean; +/** + * Get component name off of a propType assignment statement + * @param propTypeAssignment + * @param sourceFile + */ +export declare function getComponentName(propTypeAssignment: ts.Statement, sourceFile: ts.SourceFile): string; +/** + * Convert react stateless function to arrow function + * @example + * Before: + * function Hello(message) { + * return
{message}
+ * } + * + * After: + * const Hello = message => { + * return
{message}
+ * } + */ +export declare function convertReactStatelessFunctionToArrowFunction(statelessFunc: ts.FunctionDeclaration | ts.VariableStatement): ts.VariableStatement; +/** + * Insert an item in middle of an array after a specific item + * @param collection + * @param afterItem + * @param newItem + */ +export declare function insertAfter(collection: ArrayLike, afterItem: T, newItem: T): T[]; +/** + * Insert an item in middle of an array before a specific item + * @param collection + * @param beforeItem + * @param newItem + */ +export declare function insertBefore(collection: ArrayLike, beforeItem: T, newItems: T | T[]): T[]; +/** + * Replace an item in a collection with another item + * @param collection + * @param item + * @param newItem + */ +export declare function replaceItem(collection: ArrayLike, item: T, newItem: T): T[]; +/** + * Remove an item from a collection + * @param collection + * @param item + * @param newItem + */ +export declare function removeItem(collection: ArrayLike, item: T): T[]; diff --git a/dist/helpers/index.js b/dist/helpers/index.js new file mode 100644 index 0000000..df30b66 --- /dev/null +++ b/dist/helpers/index.js @@ -0,0 +1,182 @@ +"use strict"; +function __export(m) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; +} +Object.defineProperty(exports, "__esModule", { value: true }); +var ts = require("typescript"); +var _ = require("lodash"); +__export(require("./build-prop-type-interface")); +/** + * If a class declaration a react class? + * @param classDeclaration + * @param typeChecker + */ +function isReactComponent(classDeclaration, typeChecker) { + // Only classes that extend React.Component + if (!classDeclaration.heritageClauses) { + return false; + } + if (classDeclaration.heritageClauses.length !== 1) { + return false; + } + var firstHeritageClauses = classDeclaration.heritageClauses[0]; + if (firstHeritageClauses.token !== ts.SyntaxKind.ExtendsKeyword) { + return false; + } + var expressionWithTypeArguments = firstHeritageClauses.types[0]; + if (!expressionWithTypeArguments) { + return false; + } + // Try type checker and fallback to node text + var type = typeChecker.getTypeAtLocation(expressionWithTypeArguments); + var typeSymbol = type && type.symbol && type.symbol.name; + if (!typeSymbol) { + typeSymbol = expressionWithTypeArguments.expression.getText(); + } + if (!/React\.Component|Component/.test(typeSymbol)) { + return false; + } + return true; +} +exports.isReactComponent = isReactComponent; +/** + * Determine if a ts.HeritageClause is React HeritageClause + * + * @example `extends React.Component<{}, {}>` is a React HeritageClause + * + * @todo: this is lazy. Use the typeChecker instead + * @param clause + */ +function isReactHeritageClause(clause) { + return (clause.token === ts.SyntaxKind.ExtendsKeyword && + clause.types.length === 1 && + ts.isExpressionWithTypeArguments(clause.types[0]) && + /Component/.test(clause.types[0].expression.getText())); +} +exports.isReactHeritageClause = isReactHeritageClause; +/** + * Return true if a statement is a React propType assignment statement + * @example + * SomeComponent.propTypes = { foo: React.PropTypes.string }; + * @param statement + */ +function isReactPropTypeAssignmentStatement(statement) { + return (ts.isExpressionStatement(statement) && + ts.isBinaryExpression(statement.expression) && + statement.expression.operatorToken.kind === ts.SyntaxKind.FirstAssignment && + ts.isPropertyAccessExpression(statement.expression.left) && + /\.propTypes$|\.propTypes\..+$/.test(statement.expression.left.getText())); +} +exports.isReactPropTypeAssignmentStatement = isReactPropTypeAssignmentStatement; +/** + * Does class member have a "static" member? + * @param classMember + */ +function hasStaticModifier(classMember) { + if (!classMember.modifiers) { + return false; + } + var staticModifier = _.find(classMember.modifiers, function (modifier) { + return modifier.kind == ts.SyntaxKind.StaticKeyword; + }); + return staticModifier !== undefined; +} +exports.hasStaticModifier = hasStaticModifier; +/** + * Is class member a React "propTypes" member? + * @param classMember + * @param sourceFile + */ +function isPropTypesMember(classMember, sourceFile) { + try { + var name_1 = classMember.name !== undefined && ts.isIdentifier(classMember.name) ? classMember.name.escapedText : null; + return name_1 === 'propTypes'; + } + catch (e) { + return false; + } +} +exports.isPropTypesMember = isPropTypesMember; +/** + * Get component name off of a propType assignment statement + * @param propTypeAssignment + * @param sourceFile + */ +function getComponentName(propTypeAssignment, sourceFile) { + var text = propTypeAssignment.getText(sourceFile); + return text.substr(0, text.indexOf('.')); +} +exports.getComponentName = getComponentName; +/** + * Convert react stateless function to arrow function + * @example + * Before: + * function Hello(message) { + * return
{message}
+ * } + * + * After: + * const Hello = message => { + * return
{message}
+ * } + */ +function convertReactStatelessFunctionToArrowFunction(statelessFunc) { + if (ts.isVariableStatement(statelessFunc)) + return statelessFunc; + var funcName = statelessFunc.name || 'Component'; + var funcBody = statelessFunc.body || ts.createBlock([]); + var initializer = ts.createArrowFunction(undefined, undefined, statelessFunc.parameters, undefined, undefined, funcBody); + return ts.createVariableStatement(statelessFunc.modifiers, ts.createVariableDeclarationList([ts.createVariableDeclaration(funcName, undefined, initializer)], ts.NodeFlags.Const)); +} +exports.convertReactStatelessFunctionToArrowFunction = convertReactStatelessFunctionToArrowFunction; +/** + * Insert an item in middle of an array after a specific item + * @param collection + * @param afterItem + * @param newItem + */ +function insertAfter(collection, afterItem, newItem) { + var index = _.indexOf(collection, afterItem) + 1; + return _.slice(collection, 0, index) + .concat(newItem) + .concat(_.slice(collection, index)); +} +exports.insertAfter = insertAfter; +/** + * Insert an item in middle of an array before a specific item + * @param collection + * @param beforeItem + * @param newItem + */ +function insertBefore(collection, beforeItem, newItems) { + var index = _.indexOf(collection, beforeItem); + return _.slice(collection, 0, index) + .concat(newItems) + .concat(_.slice(collection, index)); +} +exports.insertBefore = insertBefore; +/** + * Replace an item in a collection with another item + * @param collection + * @param item + * @param newItem + */ +function replaceItem(collection, item, newItem) { + var index = _.indexOf(collection, item); + return _.slice(collection, 0, index) + .concat(newItem) + .concat(_.slice(collection, index + 1)); +} +exports.replaceItem = replaceItem; +/** + * Remove an item from a collection + * @param collection + * @param item + * @param newItem + */ +function removeItem(collection, item) { + var index = _.indexOf(collection, item); + return _.slice(collection, 0, index).concat(_.slice(collection, index + 1)); +} +exports.removeItem = removeItem; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/helpers/index.js.map b/dist/helpers/index.js.map new file mode 100644 index 0000000..09f21d8 --- /dev/null +++ b/dist/helpers/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"/Users/ethans/Documents/workspace/src/","sources":["helpers/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..4b8d2a1 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,18 @@ +import * as ts from 'typescript'; +import * as prettier from 'prettier'; +import { compile, CompilationOptions } from './compiler'; +import { reactJSMakePropsAndStateInterfaceTransformFactoryFactory } from './transforms/react-js-make-props-and-state-transform'; +import { reactRemovePropTypesAssignmentTransformFactoryFactory } from './transforms/react-remove-prop-types-assignment-transform'; +import { reactMovePropTypesToClassTransformFactoryFactory } from './transforms/react-move-prop-types-to-class-transform'; +import { collapseIntersectionInterfacesTransformFactoryFactory } from './transforms/collapse-intersection-interfaces-transform'; +import { reactRemoveStaticPropTypesMemberTransformFactoryFactory } from './transforms/react-remove-static-prop-types-member-transform'; +import { reactStatelessFunctionMakePropsTransformFactoryFactory } from './transforms/react-stateless-function-make-props-transform'; +import { reactRemovePropTypesImportTransformFactoryFactory } from './transforms/react-remove-prop-types-import'; +export { reactMovePropTypesToClassTransformFactoryFactory, reactJSMakePropsAndStateInterfaceTransformFactoryFactory, reactStatelessFunctionMakePropsTransformFactoryFactory, collapseIntersectionInterfacesTransformFactoryFactory, reactRemovePropTypesAssignmentTransformFactoryFactory, reactRemoveStaticPropTypesMemberTransformFactoryFactory, reactRemovePropTypesImportTransformFactoryFactory, compile }; +export declare const allTransforms: (typeof reactMovePropTypesToClassTransformFactoryFactory)[]; +export declare type TransformFactoryFactory = (typeChecker: ts.TypeChecker) => ts.TransformerFactory; +/** + * Run React JavaScript to TypeScript transform for file at `filePath` + * @param filePath + */ +export declare function run(filePath: string, prettierOptions?: prettier.Options, compilationOptions?: CompilationOptions): string; diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..3767321 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,38 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var compiler_1 = require("./compiler"); +exports.compile = compiler_1.compile; +var react_js_make_props_and_state_transform_1 = require("./transforms/react-js-make-props-and-state-transform"); +exports.reactJSMakePropsAndStateInterfaceTransformFactoryFactory = react_js_make_props_and_state_transform_1.reactJSMakePropsAndStateInterfaceTransformFactoryFactory; +var react_remove_prop_types_assignment_transform_1 = require("./transforms/react-remove-prop-types-assignment-transform"); +exports.reactRemovePropTypesAssignmentTransformFactoryFactory = react_remove_prop_types_assignment_transform_1.reactRemovePropTypesAssignmentTransformFactoryFactory; +var react_move_prop_types_to_class_transform_1 = require("./transforms/react-move-prop-types-to-class-transform"); +exports.reactMovePropTypesToClassTransformFactoryFactory = react_move_prop_types_to_class_transform_1.reactMovePropTypesToClassTransformFactoryFactory; +var collapse_intersection_interfaces_transform_1 = require("./transforms/collapse-intersection-interfaces-transform"); +exports.collapseIntersectionInterfacesTransformFactoryFactory = collapse_intersection_interfaces_transform_1.collapseIntersectionInterfacesTransformFactoryFactory; +var react_remove_static_prop_types_member_transform_1 = require("./transforms/react-remove-static-prop-types-member-transform"); +exports.reactRemoveStaticPropTypesMemberTransformFactoryFactory = react_remove_static_prop_types_member_transform_1.reactRemoveStaticPropTypesMemberTransformFactoryFactory; +var react_stateless_function_make_props_transform_1 = require("./transforms/react-stateless-function-make-props-transform"); +exports.reactStatelessFunctionMakePropsTransformFactoryFactory = react_stateless_function_make_props_transform_1.reactStatelessFunctionMakePropsTransformFactoryFactory; +var react_remove_prop_types_import_1 = require("./transforms/react-remove-prop-types-import"); +exports.reactRemovePropTypesImportTransformFactoryFactory = react_remove_prop_types_import_1.reactRemovePropTypesImportTransformFactoryFactory; +exports.allTransforms = [ + react_move_prop_types_to_class_transform_1.reactMovePropTypesToClassTransformFactoryFactory, + react_js_make_props_and_state_transform_1.reactJSMakePropsAndStateInterfaceTransformFactoryFactory, + react_stateless_function_make_props_transform_1.reactStatelessFunctionMakePropsTransformFactoryFactory, + collapse_intersection_interfaces_transform_1.collapseIntersectionInterfacesTransformFactoryFactory, + react_remove_prop_types_assignment_transform_1.reactRemovePropTypesAssignmentTransformFactoryFactory, + react_remove_static_prop_types_member_transform_1.reactRemoveStaticPropTypesMemberTransformFactoryFactory, + react_remove_prop_types_import_1.reactRemovePropTypesImportTransformFactoryFactory, +]; +/** + * Run React JavaScript to TypeScript transform for file at `filePath` + * @param filePath + */ +function run(filePath, prettierOptions, compilationOptions) { + if (prettierOptions === void 0) { prettierOptions = {}; } + if (compilationOptions === void 0) { compilationOptions = compiler_1.DEFAULT_COMPILATION_OPTIONS; } + return compiler_1.compile(filePath, exports.allTransforms, prettierOptions, compilationOptions); +} +exports.run = run; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/index.js.map b/dist/index.js.map new file mode 100644 index 0000000..ce25f71 --- /dev/null +++ b/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"/Users/ethans/Documents/workspace/src/","sources":["index.ts"],"names":[],"mappings":";;AAGA,uCAAsF;AAiBlF,kBAjBK,kBAAO,CAiBL;AAhBX,gHAAgI;AAU5H,mEAVK,kGAAwD,CAUL;AAT5D,0HAAkI;AAY9H,gEAZK,oGAAqD,CAYL;AAXzD,kHAAyH;AAOrH,2DAPK,2FAAgD,CAOL;AANpD,sHAAgI;AAS5H,gEATK,kGAAqD,CASL;AARzD,gIAAuI;AAUnI,kEAVK,yGAAuD,CAUL;AAT3D,4HAAoI;AAMhI,iEANK,sGAAsD,CAML;AAL1D,8FAAgH;AAS5G,4DATK,kFAAiD,CASL;AAIxC,QAAA,aAAa,GAAG;IACzB,2FAAgD;IAChD,kGAAwD;IACxD,sGAAsD;IACtD,kGAAqD;IACrD,oGAAqD;IACrD,yGAAuD;IACvD,kFAAiD;CACpD,CAAC;AAIF;;;GAGG;AACH,aACI,QAAgB,EAChB,eAAsC,EACtC,kBAAoE;IADpE,gCAAA,EAAA,oBAAsC;IACtC,mCAAA,EAAA,qBAAyC,sCAA2B;IAEpE,OAAO,kBAAO,CAAC,QAAQ,EAAE,qBAAa,EAAE,eAAe,EAAE,kBAAkB,CAAC,CAAC;AACjF,CAAC;AAND,kBAMC"} \ No newline at end of file diff --git a/dist/transforms/collapse-intersection-interfaces-transform.d.ts b/dist/transforms/collapse-intersection-interfaces-transform.d.ts new file mode 100644 index 0000000..09a87cf --- /dev/null +++ b/dist/transforms/collapse-intersection-interfaces-transform.d.ts @@ -0,0 +1,12 @@ +import * as ts from 'typescript'; +/** + * Collapse unnecessary intersections between type literals + * + * @example + * Before: + * type Foo = {foo: string;} & {bar: number;} + * + * After + * type Foo = {foo: string; bar: number;} + */ +export declare function collapseIntersectionInterfacesTransformFactoryFactory(typeChecker: ts.TypeChecker): ts.TransformerFactory; diff --git a/dist/transforms/collapse-intersection-interfaces-transform.js b/dist/transforms/collapse-intersection-interfaces-transform.js new file mode 100644 index 0000000..3792643 --- /dev/null +++ b/dist/transforms/collapse-intersection-interfaces-transform.js @@ -0,0 +1,166 @@ +"use strict"; +var __values = (this && this.__values) || function (o) { + var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; + if (m) return m.call(o); + return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; +}; +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var ts = require("typescript"); +var _ = require("lodash"); +/** + * Collapse unnecessary intersections between type literals + * + * @example + * Before: + * type Foo = {foo: string;} & {bar: number;} + * + * After + * type Foo = {foo: string; bar: number;} + */ +function collapseIntersectionInterfacesTransformFactoryFactory(typeChecker) { + return function collapseIntersectionInterfacesTransformFactory(context) { + return function collapseIntersectionInterfacesTransform(sourceFile) { + var visited = ts.visitEachChild(sourceFile, visitor, context); + ts.addEmitHelpers(visited, context.readEmitHelpers()); + return visited; + function visitor(node) { + if (ts.isTypeAliasDeclaration(node)) { + return visitTypeAliasDeclaration(node); + } + return node; + } + function visitTypeAliasDeclaration(node) { + if (ts.isIntersectionTypeNode(node.type)) { + return ts.createTypeAliasDeclaration([], [], node.name.text, [], visitIntersectionTypeNode(node.type)); + } + return node; + } + function visitIntersectionTypeNode(node) { + // Only intersection of type literals can be colapsed. + // We are currently ignoring intersections such as `{foo: string} & {bar: string} & TypeRef` + // TODO: handle mix of type references and multiple literal types + if (!node.types.every(function (typeNode) { return ts.isTypeLiteralNode(typeNode); })) { + return node; + } + // We need cast `node.type.types` to `ts.NodeArray` + // because TypeScript can't figure out `node.type.types.every(ts.isTypeLiteralNode)` + var types = node.types; + // Build a map of member names to all of types found in intersectioning type literals + // For instance {foo: string, bar: number} & { foo: number } will result in a map like this: + // Map { + // 'foo' => Set { 'string', 'number' }, + // 'bar' => Set { 'number' } + // } + var membersMap = new Map(); + // A sepecial member of type literal nodes is index signitures which don't have a name + // We use this symbol to track it in our members map + var INDEX_SIGNITUTRE_MEMBER = Symbol('Index signiture member'); + // Keep a reference of first index signiture member parameters. (ignore rest) + var indexMemberParameter = null; + // Iterate through all of type literal nodes members and add them to the members map + types.forEach(function (typeNode) { + typeNode.members.forEach(function (member) { + if (ts.isIndexSignatureDeclaration(member)) { + if (member.type !== undefined) { + if (membersMap.has(INDEX_SIGNITUTRE_MEMBER)) { + membersMap.get(INDEX_SIGNITUTRE_MEMBER).add(member.type); + } + else { + indexMemberParameter = member.parameters; + membersMap.set(INDEX_SIGNITUTRE_MEMBER, new Set([member.type])); + } + } + } + else if (ts.isPropertySignature(member)) { + if (member.type !== undefined) { + var memberName = member.name.getText(sourceFile); + // For unknown reasons, member.name.getText() is returning nothing in some cases + // This is probably because previous transformers did something with the AST that + // index of text string of member identifier is lost + // TODO: investigate + if (!memberName) { + memberName = member.name.escapedText; + } + if (membersMap.has(memberName)) { + membersMap.get(memberName).add(member.type); + } + else { + membersMap.set(memberName, new Set([member.type])); + } + } + } + }); + }); + // Result type literal members list + var finalMembers = []; + try { + // Put together the map into a type literal that has member per each map entery and type of that + // member is a union of all types in vlues for that member name in members map + // if a member has only one type, create a simple type literal for it + for (var _a = __values(membersMap.entries()), _b = _a.next(); !_b.done; _b = _a.next()) { + var _c = __read(_b.value, 2), name_1 = _c[0], types_1 = _c[1]; + if (typeof name_1 === 'symbol') { + continue; + } + // if for this name there is only one type found use the first type, otherwise make a union of all types + var resultType = types_1.size === 1 ? Array.from(types_1)[0] : createUnionType(Array.from(types_1)); + finalMembers.push(ts.createPropertySignature([], name_1, undefined, resultType, undefined)); + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (_b && !_b.done && (_d = _a.return)) _d.call(_a); + } + finally { if (e_1) throw e_1.error; } + } + // Handle index signiture member + if (membersMap.has(INDEX_SIGNITUTRE_MEMBER)) { + var indexTypes = Array.from(membersMap.get(INDEX_SIGNITUTRE_MEMBER)); + var indexType = indexTypes[0]; + if (indexTypes.length > 1) { + indexType = createUnionType(indexTypes); + } + var indexSigniture = ts.createIndexSignature([], [], indexMemberParameter, indexType); + finalMembers.push(indexSigniture); + } + // Generate one single type literal node + return ts.createTypeLiteralNode(finalMembers); + var e_1, _d; + } + /** + * Create a union type from multiple type nodes + * @param types + */ + function createUnionType(types) { + // first dedupe literal types + // TODO: this only works if all types are primitive types like string or number + var uniqueTypes = _.uniqBy(types, function (type) { return type.kind; }); + return ts.createUnionOrIntersectionTypeNode(ts.SyntaxKind.UnionType, uniqueTypes); + } + }; + }; +} +exports.collapseIntersectionInterfacesTransformFactoryFactory = collapseIntersectionInterfacesTransformFactoryFactory; +//# sourceMappingURL=collapse-intersection-interfaces-transform.js.map \ No newline at end of file diff --git a/dist/transforms/collapse-intersection-interfaces-transform.js.map b/dist/transforms/collapse-intersection-interfaces-transform.js.map new file mode 100644 index 0000000..8f6e294 --- /dev/null +++ b/dist/transforms/collapse-intersection-interfaces-transform.js.map @@ -0,0 +1 @@ +{"version":3,"file":"collapse-intersection-interfaces-transform.js","sourceRoot":"/Users/ethans/Documents/workspace/src/","sources":["transforms/collapse-intersection-interfaces-transform.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/transforms/react-js-make-props-and-state-transform.d.ts b/dist/transforms/react-js-make-props-and-state-transform.d.ts new file mode 100644 index 0000000..3dd9d0c --- /dev/null +++ b/dist/transforms/react-js-make-props-and-state-transform.d.ts @@ -0,0 +1,8 @@ +import * as ts from 'typescript'; +export declare type Factory = ts.TransformerFactory; +/** + * Get transform for transforming React code originally written in JS which does not have + * props and state generic types + * This transform will remove React component static "propTypes" member during transform + */ +export declare function reactJSMakePropsAndStateInterfaceTransformFactoryFactory(typeChecker: ts.TypeChecker): Factory; diff --git a/dist/transforms/react-js-make-props-and-state-transform.js b/dist/transforms/react-js-make-props-and-state-transform.js new file mode 100644 index 0000000..108f62c --- /dev/null +++ b/dist/transforms/react-js-make-props-and-state-transform.js @@ -0,0 +1,217 @@ +"use strict"; +var __values = (this && this.__values) || function (o) { + var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; + if (m) return m.call(o); + return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var ts = require("typescript"); +var _ = require("lodash"); +var helpers = require("../helpers"); +/** + * Get transform for transforming React code originally written in JS which does not have + * props and state generic types + * This transform will remove React component static "propTypes" member during transform + */ +function reactJSMakePropsAndStateInterfaceTransformFactoryFactory(typeChecker) { + return function reactJSMakePropsAndStateInterfaceTransformFactory(context) { + return function reactJSMakePropsAndStateInterfaceTransform(sourceFile) { + var visited = visitSourceFile(sourceFile, typeChecker); + ts.addEmitHelpers(visited, context.readEmitHelpers()); + return visited; + }; + }; +} +exports.reactJSMakePropsAndStateInterfaceTransformFactoryFactory = reactJSMakePropsAndStateInterfaceTransformFactoryFactory; +function visitSourceFile(sourceFile, typeChecker) { + var newSourceFile = sourceFile; + try { + for (var _a = __values(sourceFile.statements), _b = _a.next(); !_b.done; _b = _a.next()) { + var statement = _b.value; + if (ts.isClassDeclaration(statement) && helpers.isReactComponent(statement, typeChecker)) { + newSourceFile = visitReactClassDeclaration(statement, newSourceFile, typeChecker); + } + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (_b && !_b.done && (_c = _a.return)) _c.call(_a); + } + finally { if (e_1) throw e_1.error; } + } + return newSourceFile; + var e_1, _c; +} +function visitReactClassDeclaration(classDeclaration, sourceFile, typeChecker) { + if (!classDeclaration.heritageClauses || !classDeclaration.heritageClauses.length) { + return sourceFile; + } + var className = classDeclaration && classDeclaration.name && classDeclaration.name.getText(sourceFile); + var propType = getPropsTypeOfReactComponentClass(classDeclaration, sourceFile); + var stateType = getStateTypeOfReactComponentClass(classDeclaration, typeChecker); + var shouldMakePropTypeDeclaration = propType.members.length > 0; + var shouldMakeStateTypeDeclaration = !isStateTypeMemberEmpty(stateType); + var propTypeName = className + "Props"; + var stateTypeName = className + "State"; + var propTypeDeclaration = ts.createTypeAliasDeclaration([], [], propTypeName, [], propType); + var stateTypeDeclaration = ts.createTypeAliasDeclaration([], [], stateTypeName, [], stateType); + var propTypeRef = ts.createTypeReferenceNode(propTypeName, []); + var stateTypeRef = ts.createTypeReferenceNode(stateTypeName, []); + var newClassDeclaration = getNewReactClassDeclaration(classDeclaration, shouldMakePropTypeDeclaration ? propTypeRef : propType, shouldMakeStateTypeDeclaration ? stateTypeRef : stateType); + var allTypeDeclarations = []; + if (shouldMakePropTypeDeclaration) + allTypeDeclarations.push(propTypeDeclaration); + if (shouldMakeStateTypeDeclaration) + allTypeDeclarations.push(stateTypeDeclaration); + var statements = helpers.insertBefore(sourceFile.statements, classDeclaration, allTypeDeclarations); + statements = helpers.replaceItem(statements, classDeclaration, newClassDeclaration); + return ts.updateSourceFileNode(sourceFile, statements); +} +function getNewReactClassDeclaration(classDeclaration, propTypeRef, stateTypeRef) { + if (!classDeclaration.heritageClauses || !classDeclaration.heritageClauses.length) { + return classDeclaration; + } + var firstHeritageClause = classDeclaration.heritageClauses[0]; + var newFirstHeritageClauseTypes = helpers.replaceItem(firstHeritageClause.types, firstHeritageClause.types[0], ts.updateExpressionWithTypeArguments(firstHeritageClause.types[0], [propTypeRef, stateTypeRef], firstHeritageClause.types[0].expression)); + var newHeritageClauses = helpers.replaceItem(classDeclaration.heritageClauses, firstHeritageClause, ts.updateHeritageClause(firstHeritageClause, newFirstHeritageClauseTypes)); + return ts.updateClassDeclaration(classDeclaration, classDeclaration.decorators, classDeclaration.modifiers, classDeclaration.name, classDeclaration.typeParameters, newHeritageClauses, classDeclaration.members); +} +function getPropsTypeOfReactComponentClass(classDeclaration, sourceFile) { + var staticPropTypesMember = _.find(classDeclaration.members, function (member) { + return (ts.isPropertyDeclaration(member) && + helpers.hasStaticModifier(member) && + helpers.isPropTypesMember(member, sourceFile)); + }); + if (staticPropTypesMember !== undefined && + ts.isPropertyDeclaration(staticPropTypesMember) && // check to satisfy type checker + staticPropTypesMember.initializer && + ts.isObjectLiteralExpression(staticPropTypesMember.initializer)) { + return helpers.buildInterfaceFromPropTypeObjectLiteral(staticPropTypesMember.initializer); + } + var staticPropTypesGetterMember = _.find(classDeclaration.members, function (member) { + return (ts.isGetAccessorDeclaration(member) && + helpers.hasStaticModifier(member) && + helpers.isPropTypesMember(member, sourceFile)); + }); + if (staticPropTypesGetterMember !== undefined && + ts.isGetAccessorDeclaration(staticPropTypesGetterMember) // check to satisfy typechecker + ) { + var returnStatement = _.find(staticPropTypesGetterMember.body.statements, function (statement) { + return ts.isReturnStatement(statement); + }); + if (returnStatement !== undefined && + ts.isReturnStatement(returnStatement) && // check to satisfy typechecker + returnStatement.expression && + ts.isObjectLiteralExpression(returnStatement.expression)) { + return helpers.buildInterfaceFromPropTypeObjectLiteral(returnStatement.expression); + } + } + return ts.createTypeLiteralNode([]); +} +function getStateTypeOfReactComponentClass(classDeclaration, typeChecker) { + var initialState = getInitialStateFromClassDeclaration(classDeclaration, typeChecker); + var initialStateIsVoid = initialState.kind === ts.SyntaxKind.VoidKeyword; + var collectedStateTypes = getStateLookingForSetStateCalls(classDeclaration, typeChecker); + if (!collectedStateTypes.length && initialStateIsVoid) { + return ts.createTypeLiteralNode([]); + } + if (!initialStateIsVoid) { + collectedStateTypes.push(initialState); + } + return ts.createUnionOrIntersectionTypeNode(ts.SyntaxKind.IntersectionType, collectedStateTypes); +} +/** + * Get initial state of a React component looking for state value initially set + * @param classDeclaration + * @param typeChecker + */ +function getInitialStateFromClassDeclaration(classDeclaration, typeChecker) { + // initial state class member + var initialStateMember = _.find(classDeclaration.members, function (member) { + try { + return ts.isPropertyDeclaration(member) && member.name && member.name.getText() === 'state'; + } + catch (e) { + return false; + } + }); + if (initialStateMember && ts.isPropertyDeclaration(initialStateMember) && initialStateMember.initializer) { + var type = typeChecker.getTypeAtLocation(initialStateMember.initializer); + return typeChecker.typeToTypeNode(type); + } + // Initial state in constructor + var constructor = _.find(classDeclaration.members, function (member) { return member.kind === ts.SyntaxKind.Constructor; }); + if (constructor && constructor.body) { + try { + for (var _a = __values(constructor.body.statements), _b = _a.next(); !_b.done; _b = _a.next()) { + var statement = _b.value; + if (ts.isExpressionStatement(statement) && + ts.isBinaryExpression(statement.expression) && + statement.expression.left.getText() === 'this.state') { + return typeChecker.typeToTypeNode(typeChecker.getTypeAtLocation(statement.expression.right)); + } + } + } + catch (e_2_1) { e_2 = { error: e_2_1 }; } + finally { + try { + if (_b && !_b.done && (_c = _a.return)) _c.call(_a); + } + finally { if (e_2) throw e_2.error; } + } + } + // No initial state, fall back to void + return ts.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword); + var e_2, _c; +} +/** + * Look for setState() function calls to collect the state interface in a React class component + * @param classDeclaration + * @param typeChecker + */ +function getStateLookingForSetStateCalls(classDeclaration, typeChecker) { + var typeNodes = []; + try { + for (var _a = __values(classDeclaration.members), _b = _a.next(); !_b.done; _b = _a.next()) { + var member = _b.value; + if (member && ts.isMethodDeclaration(member) && member.body) { + lookForSetState(member.body); + } + } + } + catch (e_3_1) { e_3 = { error: e_3_1 }; } + finally { + try { + if (_b && !_b.done && (_c = _a.return)) _c.call(_a); + } + finally { if (e_3) throw e_3.error; } + } + return typeNodes; + function lookForSetState(node) { + ts.forEachChild(node, lookForSetState); + if (ts.isExpressionStatement(node) && + ts.isCallExpression(node.expression) && + node.expression.expression.getText().match(/setState/)) { + var type = typeChecker.getTypeAtLocation(node.expression.arguments[0]); + typeNodes.push(typeChecker.typeToTypeNode(type)); + } + } + var e_3, _c; +} +function isStateTypeMemberEmpty(stateType) { + // Only need to handle TypeLiteralNode & IntersectionTypeNode + if (ts.isTypeLiteralNode(stateType)) { + return stateType.members.length === 0; + } + if (!ts.isIntersectionTypeNode(stateType)) { + return true; + } + return stateType.types.every(isStateTypeMemberEmpty); +} +//# sourceMappingURL=react-js-make-props-and-state-transform.js.map \ No newline at end of file diff --git a/dist/transforms/react-js-make-props-and-state-transform.js.map b/dist/transforms/react-js-make-props-and-state-transform.js.map new file mode 100644 index 0000000..84567f8 --- /dev/null +++ b/dist/transforms/react-js-make-props-and-state-transform.js.map @@ -0,0 +1 @@ +{"version":3,"file":"react-js-make-props-and-state-transform.js","sourceRoot":"/Users/ethans/Documents/workspace/src/","sources":["transforms/react-js-make-props-and-state-transform.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/transforms/react-move-prop-types-to-class-transform.d.ts b/dist/transforms/react-move-prop-types-to-class-transform.d.ts new file mode 100644 index 0000000..5f236a9 --- /dev/null +++ b/dist/transforms/react-move-prop-types-to-class-transform.d.ts @@ -0,0 +1,28 @@ +import * as ts from 'typescript'; +export declare type Factory = ts.TransformerFactory; +/** + * Move Component.propTypes statements into class as a static member of the class + * if React component is defined using a class + * + * Note: This transform assumes React component declaration and propTypes assignment statement + * are both on root of the source file + * + * @example + * Before: + * class SomeComponent extends React.Component<{foo: number;}, {bar: string;}> {} + * SomeComponent.propTypes = { foo: React.PropTypes.string } + * + * After + * class SomeComponent extends React.Component<{foo: number;}, {bar: string;}> { + * static propTypes = { foo: React.PropTypes.string } + * } + * + * @todo + * This is not supporting multiple statements for a single class yet + * ``` + * class SomeComponent extends React.Component<{foo: number;}, {bar: string;}> {} + * SomeComponent.propTypes = { foo: React.PropTypes.string } + * SomeComponent.propTypes.bar = React.PropTypes.number; + * ``` + */ +export declare function reactMovePropTypesToClassTransformFactoryFactory(typeChecker: ts.TypeChecker): Factory; diff --git a/dist/transforms/react-move-prop-types-to-class-transform.js b/dist/transforms/react-move-prop-types-to-class-transform.js new file mode 100644 index 0000000..08065fb --- /dev/null +++ b/dist/transforms/react-move-prop-types-to-class-transform.js @@ -0,0 +1,123 @@ +"use strict"; +var __values = (this && this.__values) || function (o) { + var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; + if (m) return m.call(o); + return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; +}; +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +var __spread = (this && this.__spread) || function () { + for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); + return ar; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var ts = require("typescript"); +var _ = require("lodash"); +var helpers = require("../helpers"); +/** + * Move Component.propTypes statements into class as a static member of the class + * if React component is defined using a class + * + * Note: This transform assumes React component declaration and propTypes assignment statement + * are both on root of the source file + * + * @example + * Before: + * class SomeComponent extends React.Component<{foo: number;}, {bar: string;}> {} + * SomeComponent.propTypes = { foo: React.PropTypes.string } + * + * After + * class SomeComponent extends React.Component<{foo: number;}, {bar: string;}> { + * static propTypes = { foo: React.PropTypes.string } + * } + * + * @todo + * This is not supporting multiple statements for a single class yet + * ``` + * class SomeComponent extends React.Component<{foo: number;}, {bar: string;}> {} + * SomeComponent.propTypes = { foo: React.PropTypes.string } + * SomeComponent.propTypes.bar = React.PropTypes.number; + * ``` + */ +function reactMovePropTypesToClassTransformFactoryFactory(typeChecker) { + return function reactMovePropTypesToClassTransformFactory(context) { + return function reactMovePropTypesToClassTransform(sourceFile) { + var visited = visitSourceFile(sourceFile, typeChecker); + ts.addEmitHelpers(visited, context.readEmitHelpers()); + return visited; + }; + }; +} +exports.reactMovePropTypesToClassTransformFactoryFactory = reactMovePropTypesToClassTransformFactoryFactory; +/** + * Make the move from propType statement to static member + * @param sourceFile + * @param typeChecker + */ +function visitSourceFile(sourceFile, typeChecker) { + var statements = sourceFile.statements; + // Look for propType assignment statements + var propTypeAssignments = statements.filter(function (statement) { + return helpers.isReactPropTypeAssignmentStatement(statement); + }); + var _loop_1 = function (propTypeAssignment) { + // Look for the class declarations with the same name + var componentName = helpers.getComponentName(propTypeAssignment, sourceFile); + var classStatement = _.find(statements, function (statement) { + return ts.isClassDeclaration(statement) && + statement.name !== undefined && + statement.name.getText(sourceFile) === componentName; + }); // Type weirdness + // && helpers.isBinaryExpression(propTypeAssignment.expression) is redundant to satisfy the type checker + if (classStatement && ts.isBinaryExpression(propTypeAssignment.expression)) { + var newClassStatement = addStaticMemberToClass(classStatement, 'propTypes', propTypeAssignment.expression.right); + statements = ts.createNodeArray(helpers.replaceItem(statements, classStatement, newClassStatement)); + } + }; + try { + for (var propTypeAssignments_1 = __values(propTypeAssignments), propTypeAssignments_1_1 = propTypeAssignments_1.next(); !propTypeAssignments_1_1.done; propTypeAssignments_1_1 = propTypeAssignments_1.next()) { + var propTypeAssignment = propTypeAssignments_1_1.value; + _loop_1(propTypeAssignment); + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (propTypeAssignments_1_1 && !propTypeAssignments_1_1.done && (_a = propTypeAssignments_1.return)) _a.call(propTypeAssignments_1); + } + finally { if (e_1) throw e_1.error; } + } + return ts.updateSourceFileNode(sourceFile, statements); + var e_1, _a; +} +/** + * Insert a new static member into a class + * @param classDeclaration + * @param name + * @param value + */ +function addStaticMemberToClass(classDeclaration, name, value) { + var staticModifier = ts.createToken(ts.SyntaxKind.StaticKeyword); + var propertyDeclaration = ts.createProperty([], [staticModifier], name, undefined, undefined, value); + return ts.updateClassDeclaration(classDeclaration, classDeclaration.decorators, classDeclaration.modifiers, classDeclaration.name, classDeclaration.typeParameters, ts.createNodeArray(classDeclaration.heritageClauses), ts.createNodeArray(__spread([propertyDeclaration], classDeclaration.members))); +} +//# sourceMappingURL=react-move-prop-types-to-class-transform.js.map \ No newline at end of file diff --git a/dist/transforms/react-move-prop-types-to-class-transform.js.map b/dist/transforms/react-move-prop-types-to-class-transform.js.map new file mode 100644 index 0000000..362f7a5 --- /dev/null +++ b/dist/transforms/react-move-prop-types-to-class-transform.js.map @@ -0,0 +1 @@ +{"version":3,"file":"react-move-prop-types-to-class-transform.js","sourceRoot":"/Users/ethans/Documents/workspace/src/","sources":["transforms/react-move-prop-types-to-class-transform.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+BAAiC;AACjC,0BAA4B;AAE5B,oCAAsC;AAItC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,0DAAiE,WAA2B;IACxF,OAAO,mDAAmD,OAAiC;QACvF,OAAO,4CAA4C,UAAyB;YACxE,IAAM,OAAO,GAAG,eAAe,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;YACzD,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;YACtD,OAAO,OAAO,CAAC;QACnB,CAAC,CAAC;IACN,CAAC,CAAC;AACN,CAAC;AARD,4GAQC;AAED;;;;GAIG;AACH,yBAAyB,UAAyB,EAAE,WAA2B;IAC3E,IAAI,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC;IAEvC,0CAA0C;IAC1C,IAAM,mBAAmB,GAAG,UAAU,CAAC,MAAM,CAAC,UAAA,SAAS;QACnD,OAAA,OAAO,CAAC,kCAAkC,CAAC,SAAS,CAAC;IAArD,CAAqD,CAC5B,CAAC;4BAEnB,kBAAkB;QACzB,qDAAqD;QACrD,IAAM,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAC;QAE/E,IAAM,cAAc,GAAI,CAAC,CAAC,IAAI,CAC1B,UAAU,EACV,UAAA,SAAS;YACL,OAAA,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC;gBAChC,SAAS,CAAC,IAAI,KAAK,SAAS;gBAC5B,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,aAAa;QAFpD,CAEoD,CAC7B,CAAC,CAAC,iBAAiB;QAElD,wGAAwG;QACxG,IAAI,cAAc,IAAI,EAAE,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,UAAU,CAAC,EAAE;YACxE,IAAM,iBAAiB,GAAG,sBAAsB,CAC5C,cAAc,EACd,WAAW,EACX,kBAAkB,CAAC,UAAU,CAAC,KAAK,CACtC,CAAC;YACF,UAAU,GAAG,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,WAAW,CAAC,UAAU,EAAE,cAAc,EAAE,iBAAiB,CAAC,CAAC,CAAC;SACvG;IACL,CAAC;;QArBD,KAAiC,IAAA,wBAAA,SAAA,mBAAmB,CAAA,wDAAA;YAA/C,IAAM,kBAAkB,gCAAA;oBAAlB,kBAAkB;SAqB5B;;;;;;;;;IAED,OAAO,EAAE,CAAC,oBAAoB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;;AAC3D,CAAC;AAED;;;;;GAKG;AACH,gCAAgC,gBAAqC,EAAE,IAAY,EAAE,KAAoB;IACrG,IAAM,cAAc,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IACnE,IAAM,mBAAmB,GAAG,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IACvG,OAAO,EAAE,CAAC,sBAAsB,CAC5B,gBAAgB,EAChB,gBAAgB,CAAC,UAAU,EAC3B,gBAAgB,CAAC,SAAS,EAC1B,gBAAgB,CAAC,IAAI,EACrB,gBAAgB,CAAC,cAAc,EAC/B,EAAE,CAAC,eAAe,CAAC,gBAAgB,CAAC,eAAe,CAAC,EACpD,EAAE,CAAC,eAAe,WAAE,mBAAmB,GAAK,gBAAgB,CAAC,OAAO,EAAE,CACzE,CAAC;AACN,CAAC"} \ No newline at end of file diff --git a/dist/transforms/react-remove-prop-types-assignment-transform.d.ts b/dist/transforms/react-remove-prop-types-assignment-transform.d.ts new file mode 100644 index 0000000..3cbad54 --- /dev/null +++ b/dist/transforms/react-remove-prop-types-assignment-transform.d.ts @@ -0,0 +1,14 @@ +import * as ts from 'typescript'; +export declare type Factory = ts.TransformerFactory; +/** + * Remove Component.propTypes statements + * + * @example + * Before: + * class SomeComponent extends React.Component<{foo: number;}, {bar: string;}> {} + * SomeComponent.propTypes = { foo: React.PropTypes.string } + * + * After + * class SomeComponent extends React.Component<{foo: number;}, {bar: string;}> {} + */ +export declare function reactRemovePropTypesAssignmentTransformFactoryFactory(typeChecker: ts.TypeChecker): Factory; diff --git a/dist/transforms/react-remove-prop-types-assignment-transform.js b/dist/transforms/react-remove-prop-types-assignment-transform.js new file mode 100644 index 0000000..9546468 --- /dev/null +++ b/dist/transforms/react-remove-prop-types-assignment-transform.js @@ -0,0 +1,26 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var ts = require("typescript"); +var helpers = require("../helpers"); +/** + * Remove Component.propTypes statements + * + * @example + * Before: + * class SomeComponent extends React.Component<{foo: number;}, {bar: string;}> {} + * SomeComponent.propTypes = { foo: React.PropTypes.string } + * + * After + * class SomeComponent extends React.Component<{foo: number;}, {bar: string;}> {} + */ +function reactRemovePropTypesAssignmentTransformFactoryFactory(typeChecker) { + return function reactRemovePropTypesAssignmentTransformFactory(context) { + return function reactRemovePropTypesAssignmentTransform(sourceFile) { + var visited = ts.updateSourceFileNode(sourceFile, sourceFile.statements.filter(function (s) { return !helpers.isReactPropTypeAssignmentStatement(s); })); + ts.addEmitHelpers(visited, context.readEmitHelpers()); + return visited; + }; + }; +} +exports.reactRemovePropTypesAssignmentTransformFactoryFactory = reactRemovePropTypesAssignmentTransformFactoryFactory; +//# sourceMappingURL=react-remove-prop-types-assignment-transform.js.map \ No newline at end of file diff --git a/dist/transforms/react-remove-prop-types-assignment-transform.js.map b/dist/transforms/react-remove-prop-types-assignment-transform.js.map new file mode 100644 index 0000000..e82bd62 --- /dev/null +++ b/dist/transforms/react-remove-prop-types-assignment-transform.js.map @@ -0,0 +1 @@ +{"version":3,"file":"react-remove-prop-types-assignment-transform.js","sourceRoot":"/Users/ethans/Documents/workspace/src/","sources":["transforms/react-remove-prop-types-assignment-transform.ts"],"names":[],"mappings":";;AAAA,+BAAiC;AAEjC,oCAAsC;AAItC;;;;;;;;;;GAUG;AACH,+DAAsE,WAA2B;IAC7F,OAAO,wDAAwD,OAAiC;QAC5F,OAAO,iDAAiD,UAAyB;YAC7E,IAAM,OAAO,GAAG,EAAE,CAAC,oBAAoB,CACnC,UAAU,EACV,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,CAAC,EAA9C,CAA8C,CAAC,CACpF,CAAC;YACF,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;YACtD,OAAO,OAAO,CAAC;QACnB,CAAC,CAAC;IACN,CAAC,CAAC;AACN,CAAC;AAXD,sHAWC"} \ No newline at end of file diff --git a/dist/transforms/react-remove-prop-types-import.d.ts b/dist/transforms/react-remove-prop-types-import.d.ts new file mode 100644 index 0000000..39a2fbf --- /dev/null +++ b/dist/transforms/react-remove-prop-types-import.d.ts @@ -0,0 +1,15 @@ +import * as ts from 'typescript'; +export declare type Factory = ts.TransformerFactory; +/** + * Remove `import PropTypes from 'prop-types'` or + * `import { PropTypes } from 'react'` + * + * @example + * Before: + * import PropTypes from 'prop-types' + * import React, { PropTypes } from 'react' + * + * After: + * import React from 'react' + */ +export declare function reactRemovePropTypesImportTransformFactoryFactory(typeChecker: ts.TypeChecker): Factory; diff --git a/dist/transforms/react-remove-prop-types-import.js b/dist/transforms/react-remove-prop-types-import.js new file mode 100644 index 0000000..24efe1a --- /dev/null +++ b/dist/transforms/react-remove-prop-types-import.js @@ -0,0 +1,52 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var ts = require("typescript"); +/** + * Remove `import PropTypes from 'prop-types'` or + * `import { PropTypes } from 'react'` + * + * @example + * Before: + * import PropTypes from 'prop-types' + * import React, { PropTypes } from 'react' + * + * After: + * import React from 'react' + */ +function reactRemovePropTypesImportTransformFactoryFactory(typeChecker) { + return function reactRemovePropTypesImportTransformFactory(context) { + return function reactRemovePropTypesImportTransform(sourceFile) { + var visited = ts.updateSourceFileNode(sourceFile, sourceFile.statements + .filter(function (s) { + return !(ts.isImportDeclaration(s) && + ts.isStringLiteral(s.moduleSpecifier) && + s.moduleSpecifier.text === 'prop-types'); + }) + .map(updateReactImportIfNeeded)); + ts.addEmitHelpers(visited, context.readEmitHelpers()); + return visited; + }; + }; +} +exports.reactRemovePropTypesImportTransformFactoryFactory = reactRemovePropTypesImportTransformFactoryFactory; +function updateReactImportIfNeeded(statement) { + if (!ts.isImportDeclaration(statement) || + !ts.isStringLiteral(statement.moduleSpecifier) || + statement.moduleSpecifier.text !== 'react' || + !statement.importClause || + !statement.importClause.namedBindings || + !ts.isNamedImports(statement.importClause.namedBindings)) { + return statement; + } + var namedBindings = statement.importClause.namedBindings; + var newNamedBindingElements = namedBindings.elements.filter(function (elm) { return elm.name.text !== 'PropTypes'; }); + if (newNamedBindingElements.length === namedBindings.elements.length) { + // Means it has no 'PropTypes' named import + return statement; + } + var newImportClause = ts.updateImportClause(statement.importClause, statement.importClause.name, newNamedBindingElements.length === 0 + ? undefined + : ts.updateNamedImports(namedBindings, newNamedBindingElements)); + return ts.updateImportDeclaration(statement, statement.decorators, statement.modifiers, newImportClause, statement.moduleSpecifier); +} +//# sourceMappingURL=react-remove-prop-types-import.js.map \ No newline at end of file diff --git a/dist/transforms/react-remove-prop-types-import.js.map b/dist/transforms/react-remove-prop-types-import.js.map new file mode 100644 index 0000000..3cdb181 --- /dev/null +++ b/dist/transforms/react-remove-prop-types-import.js.map @@ -0,0 +1 @@ +{"version":3,"file":"react-remove-prop-types-import.js","sourceRoot":"/Users/ethans/Documents/workspace/src/","sources":["transforms/react-remove-prop-types-import.ts"],"names":[],"mappings":";;AAAA,+BAAiC;AAOjC;;;;;;;;;;;GAWG;AACH,2DAAkE,WAA2B;IACzF,OAAO,oDAAoD,OAAiC;QACxF,OAAO,6CAA6C,UAAyB;YACzE,IAAM,OAAO,GAAG,EAAE,CAAC,oBAAoB,CACnC,UAAU,EACV,UAAU,CAAC,UAAU;iBAChB,MAAM,CAAC,UAAA,CAAC;gBACL,OAAO,CAAC,CACJ,EAAE,CAAC,mBAAmB,CAAC,CAAC,CAAC;oBACzB,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC;oBACrC,CAAC,CAAC,eAAe,CAAC,IAAI,KAAK,YAAY,CAC1C,CAAC;YACN,CAAC,CAAC;iBACD,GAAG,CAAC,yBAAyB,CAAC,CACtC,CAAC;YACF,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;YACtD,OAAO,OAAO,CAAC;QACnB,CAAC,CAAC;IACN,CAAC,CAAC;AACN,CAAC;AAnBD,8GAmBC;AAED,mCAAmC,SAAuB;IACtD,IACI,CAAC,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC;QAClC,CAAC,EAAE,CAAC,eAAe,CAAC,SAAS,CAAC,eAAe,CAAC;QAC9C,SAAS,CAAC,eAAe,CAAC,IAAI,KAAK,OAAO;QAC1C,CAAC,SAAS,CAAC,YAAY;QACvB,CAAC,SAAS,CAAC,YAAY,CAAC,aAAa;QACrC,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC,YAAY,CAAC,aAAa,CAAC,EAC1D;QACE,OAAO,SAAS,CAAC;KACpB;IAED,IAAM,aAAa,GAAG,SAAS,CAAC,YAAY,CAAC,aAAa,CAAC;IAC3D,IAAM,uBAAuB,GAAG,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAA,GAAG,IAAI,OAAA,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,WAAW,EAA7B,CAA6B,CAAC,CAAC;IAEpG,IAAI,uBAAuB,CAAC,MAAM,KAAK,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE;QAClE,2CAA2C;QAC3C,OAAO,SAAS,CAAC;KACpB;IAED,IAAM,eAAe,GAAG,EAAE,CAAC,kBAAkB,CACzC,SAAS,CAAC,YAAY,EACtB,SAAS,CAAC,YAAY,CAAC,IAAI,EAC3B,uBAAuB,CAAC,MAAM,KAAK,CAAC;QAChC,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,EAAE,CAAC,kBAAkB,CAAC,aAAa,EAAE,uBAAuB,CAAC,CACtE,CAAC;IAEF,OAAO,EAAE,CAAC,uBAAuB,CAC7B,SAAS,EACT,SAAS,CAAC,UAAU,EACpB,SAAS,CAAC,SAAS,EACnB,eAAe,EACf,SAAS,CAAC,eAAe,CAC5B,CAAC;AACN,CAAC"} \ No newline at end of file diff --git a/dist/transforms/react-remove-static-prop-types-member-transform.d.ts b/dist/transforms/react-remove-static-prop-types-member-transform.d.ts new file mode 100644 index 0000000..480264e --- /dev/null +++ b/dist/transforms/react-remove-static-prop-types-member-transform.d.ts @@ -0,0 +1,17 @@ +import * as ts from 'typescript'; +export declare type Factory = ts.TransformerFactory; +/** + * Remove static propTypes + * + * @example + * Before: + * class SomeComponent extends React.Component<{foo: number;}, {bar: string;}> { + * static propTypes = { + * foo: React.PropTypes.number.isRequired, + * } + * } + * + * After: + * class SomeComponent extends React.Component<{foo: number;}, {bar: string;}> {} + */ +export declare function reactRemoveStaticPropTypesMemberTransformFactoryFactory(typeChecker: ts.TypeChecker): Factory; diff --git a/dist/transforms/react-remove-static-prop-types-member-transform.js b/dist/transforms/react-remove-static-prop-types-member-transform.js new file mode 100644 index 0000000..a7e0d63 --- /dev/null +++ b/dist/transforms/react-remove-static-prop-types-member-transform.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var ts = require("typescript"); +var helpers = require("../helpers"); +/** + * Remove static propTypes + * + * @example + * Before: + * class SomeComponent extends React.Component<{foo: number;}, {bar: string;}> { + * static propTypes = { + * foo: React.PropTypes.number.isRequired, + * } + * } + * + * After: + * class SomeComponent extends React.Component<{foo: number;}, {bar: string;}> {} + */ +function reactRemoveStaticPropTypesMemberTransformFactoryFactory(typeChecker) { + return function reactRemoveStaticPropTypesMemberTransformFactory(context) { + return function reactRemoveStaticPropTypesMemberTransform(sourceFile) { + var visited = ts.visitEachChild(sourceFile, visitor, context); + ts.addEmitHelpers(visited, context.readEmitHelpers()); + return visited; + function visitor(node) { + if (ts.isClassDeclaration(node) && helpers.isReactComponent(node, typeChecker)) { + return ts.updateClassDeclaration(node, node.decorators, node.modifiers, node.name, node.typeParameters, ts.createNodeArray(node.heritageClauses), node.members.filter(function (member) { + if (ts.isPropertyDeclaration(member) && + helpers.hasStaticModifier(member) && + helpers.isPropTypesMember(member, sourceFile)) { + return false; + } + // propTypes getter + if (ts.isGetAccessorDeclaration(member) && + helpers.hasStaticModifier(member) && + helpers.isPropTypesMember(member, sourceFile)) { + return false; + } + return true; + })); + } + return node; + } + }; + }; +} +exports.reactRemoveStaticPropTypesMemberTransformFactoryFactory = reactRemoveStaticPropTypesMemberTransformFactoryFactory; +//# sourceMappingURL=react-remove-static-prop-types-member-transform.js.map \ No newline at end of file diff --git a/dist/transforms/react-remove-static-prop-types-member-transform.js.map b/dist/transforms/react-remove-static-prop-types-member-transform.js.map new file mode 100644 index 0000000..0ab271b --- /dev/null +++ b/dist/transforms/react-remove-static-prop-types-member-transform.js.map @@ -0,0 +1 @@ +{"version":3,"file":"react-remove-static-prop-types-member-transform.js","sourceRoot":"/Users/ethans/Documents/workspace/src/","sources":["transforms/react-remove-static-prop-types-member-transform.ts"],"names":[],"mappings":";;AAAA,+BAAiC;AAEjC,oCAAsC;AAItC;;;;;;;;;;;;;GAaG;AACH,iEAAwE,WAA2B;IAC/F,OAAO,0DAA0D,OAAiC;QAC9F,OAAO,mDAAmD,UAAyB;YAC/E,IAAM,OAAO,GAAG,EAAE,CAAC,cAAc,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YAChE,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;YACtD,OAAO,OAAO,CAAC;YAEf,iBAAiB,IAAa;gBAC1B,IAAI,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,gBAAgB,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE;oBAC5E,OAAO,EAAE,CAAC,sBAAsB,CAC5B,IAAI,EACJ,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,cAAc,EACnB,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,eAAe,CAAC,EACxC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,UAAA,MAAM;wBACtB,IACI,EAAE,CAAC,qBAAqB,CAAC,MAAM,CAAC;4BAChC,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC;4BACjC,OAAO,CAAC,iBAAiB,CAAC,MAAM,EAAE,UAAU,CAAC,EAC/C;4BACE,OAAO,KAAK,CAAC;yBAChB;wBAED,mBAAmB;wBACnB,IACI,EAAE,CAAC,wBAAwB,CAAC,MAAM,CAAC;4BACnC,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC;4BACjC,OAAO,CAAC,iBAAiB,CAAC,MAAM,EAAE,UAAU,CAAC,EAC/C;4BACE,OAAO,KAAK,CAAC;yBAChB;wBACD,OAAO,IAAI,CAAC;oBAChB,CAAC,CAAC,CACL,CAAC;iBACL;gBACD,OAAO,IAAI,CAAC;YAChB,CAAC;QACL,CAAC,CAAC;IACN,CAAC,CAAC;AACN,CAAC;AAzCD,0HAyCC"} \ No newline at end of file diff --git a/dist/transforms/react-stateless-function-make-props-transform.d.ts b/dist/transforms/react-stateless-function-make-props-transform.d.ts new file mode 100644 index 0000000..7f10a84 --- /dev/null +++ b/dist/transforms/react-stateless-function-make-props-transform.d.ts @@ -0,0 +1,31 @@ +import * as ts from 'typescript'; +export declare type Factory = ts.TransformerFactory; +/** + * Transform react stateless components + * + * @example + * Before: + * const Hello = ({ message }) => { + * return
hello {message}
+ * } + * // Or: + * // const Hello = ({ message }) =>
hello {message}
+ * + * Hello.propTypes = { + * message: React.PropTypes.string, + * } + * + * After: + * Type HelloProps = { + * message: string; + * } + * + * const Hello: React.SFC = ({ message }) => { + * return
hello {message}
+ * } + * + * Hello.propTypes = { + * message: React.PropTypes.string, + * } + */ +export declare function reactStatelessFunctionMakePropsTransformFactoryFactory(typeChecker: ts.TypeChecker): Factory; diff --git a/dist/transforms/react-stateless-function-make-props-transform.js b/dist/transforms/react-stateless-function-make-props-transform.js new file mode 100644 index 0000000..2864bfd --- /dev/null +++ b/dist/transforms/react-stateless-function-make-props-transform.js @@ -0,0 +1,114 @@ +"use strict"; +var __values = (this && this.__values) || function (o) { + var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; + if (m) return m.call(o); + return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var ts = require("typescript"); +var _ = require("lodash"); +var helpers = require("../helpers"); +/** + * Transform react stateless components + * + * @example + * Before: + * const Hello = ({ message }) => { + * return
hello {message}
+ * } + * // Or: + * // const Hello = ({ message }) =>
hello {message}
+ * + * Hello.propTypes = { + * message: React.PropTypes.string, + * } + * + * After: + * Type HelloProps = { + * message: string; + * } + * + * const Hello: React.SFC = ({ message }) => { + * return
hello {message}
+ * } + * + * Hello.propTypes = { + * message: React.PropTypes.string, + * } + */ +function reactStatelessFunctionMakePropsTransformFactoryFactory(typeChecker) { + return function reactStatelessFunctionMakePropsTransformFactory(context) { + return function reactStatelessFunctionMakePropsTransform(sourceFile) { + var visited = visitSourceFile(sourceFile, typeChecker); + ts.addEmitHelpers(visited, context.readEmitHelpers()); + return visited; + }; + }; +} +exports.reactStatelessFunctionMakePropsTransformFactoryFactory = reactStatelessFunctionMakePropsTransformFactoryFactory; +function visitSourceFile(sourceFile, typeChecker) { + // Look for propType assignment statements + var propTypeAssignments = sourceFile.statements.filter(function (statement) { + return helpers.isReactPropTypeAssignmentStatement(statement); + }); + var newSourceFile = sourceFile; + var _loop_1 = function (propTypeAssignment) { + var componentName = helpers.getComponentName(propTypeAssignment, newSourceFile); + var funcComponent = _.find(newSourceFile.statements, function (s) { + return ((ts.isFunctionDeclaration(s) && s.name !== undefined && s.name.getText() === componentName) || + (ts.isVariableStatement(s) && s.declarationList.declarations[0].name.getText() === componentName)); + }); // Type weirdness + if (funcComponent) { + newSourceFile = visitReactStatelessComponent(funcComponent, propTypeAssignment, newSourceFile); + } + }; + try { + for (var propTypeAssignments_1 = __values(propTypeAssignments), propTypeAssignments_1_1 = propTypeAssignments_1.next(); !propTypeAssignments_1_1.done; propTypeAssignments_1_1 = propTypeAssignments_1.next()) { + var propTypeAssignment = propTypeAssignments_1_1.value; + _loop_1(propTypeAssignment); + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (propTypeAssignments_1_1 && !propTypeAssignments_1_1.done && (_a = propTypeAssignments_1.return)) _a.call(propTypeAssignments_1); + } + finally { if (e_1) throw e_1.error; } + } + return newSourceFile; + var e_1, _a; +} +function visitReactStatelessComponent(component, propTypesExpressionStatement, sourceFile) { + var arrowFuncComponent = helpers.convertReactStatelessFunctionToArrowFunction(component); + var componentName = arrowFuncComponent.declarationList.declarations[0].name.getText(); + var componentInitializer = arrowFuncComponent.declarationList.declarations[0].initializer; + var propType = getPropTypesFromTypeAssignment(propTypesExpressionStatement); + var shouldMakePropTypeDeclaration = propType.members.length > 0; + var propTypeName = componentName + "Props"; + var propTypeDeclaration = ts.createTypeAliasDeclaration([], [], propTypeName, [], propType); + var propTypeRef = ts.createTypeReferenceNode(propTypeName, []); + var componentType = ts.createTypeReferenceNode(ts.createQualifiedName(ts.createIdentifier('React'), 'SFC'), [ + shouldMakePropTypeDeclaration ? propTypeRef : propType, + ]); + // replace component with ts stateless component + var typedComponent = ts.createVariableStatement(arrowFuncComponent.modifiers, ts.createVariableDeclarationList([ts.createVariableDeclaration(componentName, componentType, componentInitializer)], arrowFuncComponent.declarationList.flags)); + var statements = shouldMakePropTypeDeclaration + ? helpers.insertBefore(sourceFile.statements, component, [propTypeDeclaration]) + : sourceFile.statements; + statements = helpers.replaceItem(statements, component, typedComponent); + return ts.updateSourceFileNode(sourceFile, statements); +} +function getPropTypesFromTypeAssignment(propTypesExpressionStatement) { + if (propTypesExpressionStatement !== undefined && + ts.isBinaryExpression(propTypesExpressionStatement.expression) && + ts.isObjectLiteralExpression(propTypesExpressionStatement.expression.right)) { + return helpers.buildInterfaceFromPropTypeObjectLiteral(propTypesExpressionStatement.expression.right); + } + return ts.createTypeLiteralNode([]); +} +//# sourceMappingURL=react-stateless-function-make-props-transform.js.map \ No newline at end of file diff --git a/dist/transforms/react-stateless-function-make-props-transform.js.map b/dist/transforms/react-stateless-function-make-props-transform.js.map new file mode 100644 index 0000000..08d9fca --- /dev/null +++ b/dist/transforms/react-stateless-function-make-props-transform.js.map @@ -0,0 +1 @@ +{"version":3,"file":"react-stateless-function-make-props-transform.js","sourceRoot":"/Users/ethans/Documents/workspace/src/","sources":["transforms/react-stateless-function-make-props-transform.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/package.json b/package.json index 55994ac..6d66e5d 100644 --- a/package.json +++ b/package.json @@ -22,10 +22,16 @@ ".ts": "/node_modules/ts-jest/preprocessor.js" }, "testRegex": "(/tests/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", - "moduleFileExtensions": ["ts", "js"] + "moduleFileExtensions": [ + "ts", + "js" + ] }, "lint-staged": { - "*.{js,json,css,md,ts,tsx}": ["node_modules/.bin/prettier --write", "git add"] + "*.{js,json,css,md,ts,tsx}": [ + "node_modules/.bin/prettier --write", + "git add" + ] }, "bin": "dist/cli.js", "author": "Mohsen Azimi ",