Skip to content

Commit

Permalink
Add support for extra output in generated TS declarations
Browse files Browse the repository at this point in the history
Ref #11
  • Loading branch information
nolimits4web committed Sep 22, 2018
1 parent 309f048 commit ba9128e
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 11 deletions.
7 changes: 6 additions & 1 deletion lib/compiler-generator/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const objectIsPhenomeComponent = require('./object-is-phenome-component');
const CompilerState = require('../compiler-utils/compiler-state');
const getComponentVisitor = require('./get-component-visitor');
const parseCommentCommands = require('./parse-conditional-comments');
const parseTypescriptExtras = require('./parse-typescript-extras');
const replaceEnvironmentVars = require('./replace-environment-vars');
const removeConstantConditions = require('./remove-constant-conditions');
const processDeclarations = require('./process-declarations');
Expand All @@ -20,6 +21,8 @@ function generator(jsxTransformer, componentTransformer, typescriptGenerator) {
modifiedComponentString = parseCommentCommands(modifiedComponentString, config);
modifiedComponentString = replaceEnvironmentVars(modifiedComponentString, config);

const typescriptExtras = parseTypescriptExtras(modifiedComponentString, config);

const ast = codeToAst(modifiedComponentString);

if (!objectIsPhenomeComponent(ast)) {
Expand All @@ -36,7 +39,9 @@ function generator(jsxTransformer, componentTransformer, typescriptGenerator) {
const { helpers: jsxHelpers } = jsxTransformer({ ast, name, functional, componentNode, state, config });
componentTransformer({ ast, name, functional, componentNode, state, config, jsxHelpers });
if (config.typeScriptDefinitions && typescriptGenerator) {
typescriptGenerator({ ast, name, functional, componentNode, state, config, input });
typescriptGenerator({
ast, name, functional, componentNode, state, config, input, typescriptExtras,
});
}

processDeclarations(ast, state.declarations);
Expand Down
29 changes: 29 additions & 0 deletions lib/compiler-generator/parse-typescript-extras.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
function parseTypescripExtras(componentString, config) {
const { compiler } = config;
const extras = {
imports: [],
props: [],
instance: [],
};

const regExps = [
new RegExp('/*[ ]*?phenome-dts-([a-z]*)([^\\*]*)\\*/', 'g'),
new RegExp('//[ ]*?phenome-dts-([a-z]*)([^\\n]*)', 'g'),
new RegExp(`/*[ ]*?phenome-${compiler}-dts-([a-z]*)([^\\*]*)\\*/`, 'g'),
new RegExp(`//[ ]*?phenome-${compiler}-dts-([a-z]*)([^\\n]*)`, 'g'),
];
regExps.forEach((re) => {
let result;
// eslint-disable-next-line
while (result = re.exec(componentString)) {
let type = result[1];
const data = result[2];
if (type === 'import') type = 'imports';
if (type === 'prop') type = 'props';
extras[type].push(data.trim());
}
});

return extras;
}
module.exports = parseTypescripExtras;
43 changes: 34 additions & 9 deletions lib/compilers/react/typescript-generator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const traversePhenomeComponent = require('../../../compiler-utils/traverse-pheno

const dtsTemplate = `
import * as React from 'react';
{{imports}}
declare namespace {{name}} {
interface Props {
Expand Down Expand Up @@ -175,8 +176,8 @@ function collectEvents(componentNode) {
return events;
}

function renderProps(props, indent) {
return props
function renderProps(props, indent, extraProps) {
let propsString = props
.map((prop) => {
let type = Array.isArray(prop.type)
? prop.type.map(typeMap).join(' | ')
Expand All @@ -188,6 +189,16 @@ function renderProps(props, indent) {
})
.map(prop => prop.trim())
.join(`\n${indent}`);

if (extraProps && extraProps.length) {
propsString += propsString.length ? `\n${indent}` : '';
propsString += extraProps
.map(prop => prop.split('\n'))
.reduce((acc, val) => acc.concat(val), [])
.map(prop => prop.trim())
.join(`\n${indent}`);
}
return propsString;
}

function renderEvents(props, indent) {
Expand All @@ -202,27 +213,41 @@ function renderEvents(props, indent) {
.join(`\n${indent}`);
}

function renderMethods(methods, indent) {
return methods
function renderMethods(methods, indent, extraMethods) {
let methodsString = methods
.map((method) => { // eslint-disable-line
return `${method.name}(${method.arguments.map(a => `${a.name}? : any`).join(', ')}) : unknown`;
})
.join(`\n${indent}`);
if (extraMethods && extraMethods.length) {
methodsString += methodsString.length ? `\n${indent}` : '';
methodsString += extraMethods
.map(method => method.split('\n'))
.reduce((acc, val) => acc.concat(val), [])
.map(method => method.trim())
.join(`\n${indent}`);
}
return methodsString;
}

const generate = ({ name = 'MyComponent', componentNode, state, ast, input }) => {
const generate = ({ name = 'MyComponent', componentNode, state, ast, input, typescriptExtras }) => {
const camelCaseName = toCamelCase(name);
const props = collectProps(componentNode, ast, input);
const events = collectEvents(componentNode);
const methods = collectMethods(componentNode);
const renderedProps = renderProps(props, ' ');
const renderedProps = renderProps(props, ' ', typescriptExtras && typescriptExtras.props);
const renderedEvents = renderEvents(events, ' ');
const renderedMethods = renderMethods(methods, ' ');
const renderedMethods = renderMethods(methods, ' ', typescriptExtras && typescriptExtras.instance);

const extraImports = typescriptExtras && typescriptExtras.imports && typescriptExtras.length
? `${typescriptExtras.imports.join('\n')}\n`
: '';

const output = dtsTemplate.replace(
/({{name}})|({{props}})|({{events}})|({{methods}})/g,
/({{imports}}\n)|({{name}})|({{props}})|({{events}})|({{methods}})/g,
// eslint-disable-next-line
(_, replaceName, replaceProps, replaceEvents, replaceMethods) => {
(_, replaceImports, replaceName, replaceProps, replaceEvents, replaceMethods) => {
if (replaceImports) return extraImports;
if (replaceName) return camelCaseName;
else if (replaceProps) return renderedProps;
else if (replaceEvents) return renderedEvents;
Expand Down
19 changes: 18 additions & 1 deletion test-component/src/component.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import Mixins from './mixins';

/* phenome-dts-imports
import Something from 'somewhere';
*/
/* phenome-react-dts-imports
import SomethingReact from 'somewhere-react';
*/
const moreProps = {
moreFoo: String,
};
Expand All @@ -11,6 +16,11 @@ const deepProps = {
}
}

/* phenome-dts-instance
instanceFoo: String
instanceFoo2: String
*/

export default {
name: 'my-phenome-component',
props: {
Expand All @@ -27,6 +37,13 @@ export default {
...moreProps,
...deepProps.moreDeepProps.eventMoreDeepProps,
...Mixins.colorProps,
/* phenome-dts-props
fooDts: string
fooDts2: string
*/
/* phenome-react-dts-props
reactFoo: string
*/
},
methods: {
open(animate = true) {
Expand Down

0 comments on commit ba9128e

Please sign in to comment.