Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFR] Migrate inference code to TypeScript #2879

Merged
merged 1 commit into from
Feb 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ describe('InferredElement', () => {
});
describe('getRepresentation', () => {
it('should return a default visual representation', () => {
const DummyComponent = () => {};
const DummyComponent = () => <span />;
const dummyType = { component: DummyComponent };
const ie = new InferredElement(dummyType, { source: 'foo' });
expect(ie.getRepresentation()).toBe(
'<DummyComponent source="foo" />'
);
});
it('should return a representation based on the representation type property', () => {
const DummyComponent = () => {};
const DummyComponent = () => <span />;
const dummyType = {
component: DummyComponent,
representation: props => `hello, ${props.source}!`,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { createElement } from 'react';
import { InferredType } from './types';

class InferredElement {
constructor(type, props, children) {
this.type = type;
this.props = props;
this.children = children;
}
constructor(
private type?: InferredType,
private props?: any,
private children?: any
) {}

getElement(props = {}) {
if (!this.isDefined()) {
Expand Down
31 changes: 0 additions & 31 deletions packages/ra-core/src/inference/assertions.js

This file was deleted.

33 changes: 33 additions & 0 deletions packages/ra-core/src/inference/assertions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import parseDate from 'date-fns/parse';

export const isNumeric = (value: any) =>
!isNaN(parseFloat(value)) && isFinite(value);
export const valuesAreNumeric = (values: any[]) => values.every(isNumeric);

export const isInteger = (value: any) => Number.isInteger(value);
export const valuesAreInteger = (values: any[]) => values.every(isInteger);

export const isBoolean = (value: any) => typeof value === 'boolean';
export const valuesAreBoolean = (values: any[]) => values.every(isBoolean);

export const isString = (value: any) => typeof value === 'string';
export const valuesAreString = (values: any[]) => values.every(isString);

const HtmlRegexp = /<([A-Z][A-Z0-9]*)\b[^>]*>(.*?)<\/\1>/i;
export const isHtml = (value: any) => HtmlRegexp.test(value);
export const valuesAreHtml = (values: any[]) => values.every(isHtml);

export const isArray = (value: any) => Array.isArray(value);
export const valuesAreArray = (values: any[]) => values.every(isArray);

export const isDate = (value: any) => value instanceof Date;
export const valuesAreDate = (values: any[]) => values.every(isDate);

export const isDateString = (value: any) =>
typeof value === 'string' && !isNaN(parseDate(value).getDate());
export const valuesAreDateString = (values: any[]) =>
values.every(isDateString);

export const isObject = (value: any) =>
Object.prototype.toString.call(value) === '[object Object]';
export const valuesAreObject = (values: any[]) => values.every(isObject);
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import inferElementFromValues from './inferElementFromValues';
import getValuesFromRecords from './getValuesFromRecords';
import { InferredTypeMap } from './types';

/**
* Get a list of React-admin field components from a list of records
Expand Down Expand Up @@ -32,7 +33,7 @@ import getValuesFromRecords from './getValuesFromRecords';
* // <ReferenceField source="user_id" reference="users"><NumberField source="id" /></ReferenceField>,
* // ];
*/
export default (records, types) => {
export default (records: any[], types: InferredTypeMap) => {
const fieldValues = getValuesFromRecords(records);
return Object.keys(fieldValues)
.reduce(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
* // user_id: [123, 456],
* // }
*/
export default records =>
export default (records: any[]) =>
records.reduce((values, record) => {
Object.keys(record).forEach(fieldName => {
if (!values[fieldName]) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import React from 'react';
import React, { SFC } from 'react';
import inferElementFromValues from './inferElementFromValues';
import InferredElement from './InferredElement';

interface Props {
source: string;
reference?: string;
}
describe('inferElementFromValues', () => {
function Good() {}
function Bad() {}
function Dummy() {}
const Good: SFC<Props> = () => <span />;
const Bad: SFC<Props> = () => <span />;
const Dummy: SFC<{ [key: string]: any }> = () => <span />;

it('should return an InferredElement', () => {
const types = {
Expand All @@ -23,15 +27,6 @@ describe('inferElementFromValues', () => {
inferElementFromValues('id', ['foo'], types).getElement()
).toEqual(<Good source="id" />);
});
it('should return null if type is falsy', () => {
const types = {
id: false,
string: { component: Bad },
};
expect(
inferElementFromValues('id', ['foo'], types).getElement()
).toBeUndefined();
});
it('should return an id field for field named id', () => {
const types = {
id: { component: Good },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
valuesAreObject,
valuesAreString,
} from './assertions';
import { InferredTypeMap } from './types';

const DefaultComponent = () => <span>;</span>;
const defaultType = {
Expand Down Expand Up @@ -76,7 +77,11 @@ const hasType = (type, types) => typeof types[type] !== 'undefined';
*
* @return InferredElement
*/
const inferElementFromValues = (name, values = [], types = defaultTypes) => {
const inferElementFromValues = (
name,
values = [],
types: InferredTypeMap = defaultTypes
) => {
if (name === 'id' && hasType('id', types)) {
return new InferredElement(types.id, { source: name });
}
Expand All @@ -88,7 +93,7 @@ const inferElementFromValues = (name, values = [], types = defaultTypes) => {
types.reference,
{
source: name,
reference: reference,
reference,
},
new InferredElement(types.referenceChild)
)
Expand All @@ -102,7 +107,7 @@ const inferElementFromValues = (name, values = [], types = defaultTypes) => {
types.reference,
{
source: name,
reference: reference,
reference,
},
new InferredElement(types.referenceChild)
)
Expand All @@ -119,7 +124,7 @@ const inferElementFromValues = (name, values = [], types = defaultTypes) => {
types.referenceArray,
{
source: name,
reference: reference,
reference,
},
new InferredElement(types.referenceArrayChild)
)
Expand All @@ -136,13 +141,13 @@ const inferElementFromValues = (name, values = [], types = defaultTypes) => {
types.referenceArray,
{
source: name,
reference: reference,
reference,
},
new InferredElement(types.referenceArrayChild)
)
);
}
if (values.length == 0) {
if (values.length === 0) {
// FIXME introspect further using name
return new InferredElement(types.string, { source: name });
}
Expand Down
11 changes: 11 additions & 0 deletions packages/ra-core/src/inference/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ComponentType } from 'react';

export interface InferredType {
type?: ComponentType;
component?: ComponentType;
representation?: (props: any, children: any) => string;
}

export interface InferredTypeMap {
[key: string]: InferredType;
}