Skip to content

Commit

Permalink
Switch Node_Package from Flow to Typescript (#1250)
Browse files Browse the repository at this point in the history
And the following:
* upgrade caniuse-lite
* modify eslint config
* switch flow & tsc in rake tasks
* switch from tape to jest
* upgrade travis node version
* switch babel & tsc for node_package
  • Loading branch information
Judahmeek authored Mar 28, 2020
1 parent 2b5c313 commit 121af31
Show file tree
Hide file tree
Showing 35 changed files with 3,272 additions and 1,231 deletions.
22 changes: 22 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,38 @@ env:
browser: true
node: true
mocha: true
jest: true

overrides:
- files: ["**/*.ts", "**/*.tsx"]
parser: "@typescript-eslint/parser"
parserOptions:
ecmaVersion: 2018
sourceType: module
project: "./tsconfig.json"
extends:
- eslint:recommended
- plugin:@typescript-eslint/eslint-recommended
- plugin:@typescript-eslint/recommended
plugins:
- "@typescript-eslint"
rules:
"@typescript-eslint/no-namespace": 0

rules:
no-console: 0
function-paren-newline: 0
object-curly-newline: 0

# https://stackoverflow.com/a/59268871/5241481
import/extensions: ['error', 'ignorePackages', {"js": 'never',"ts": "never"}]

# https://github.com/benmosher/eslint-plugin-import/issues/340
import/no-extraneous-dependencies: 0

settings:
import/core-modules:
- react-redux
import/resolver:
node:
extensions: [".js", ".ts", ".d.ts"]
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ before_install:

install:
- travis_retry gem install bundler -v '>2'
- travis_retry nvm install 10.13.0
- travis_retry nvm install 13.9.0
- node -v
- travis_retry npm i -g yarn
- travis_retry bundle install
Expand Down
4 changes: 4 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
preset: 'ts-jest/presets/js-with-ts',
testEnvironment: 'jsdom',
};
10 changes: 0 additions & 10 deletions node_package/.babelrc

This file was deleted.

3 changes: 0 additions & 3 deletions node_package/.flowconfig

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
// @flow
import type { AuthenticityHeaders } from './types/index';

export default {

authenticityToken() {
const token: ?HTMLElement = document.querySelector('meta[name="csrf-token"]');
authenticityToken(): string | null {
const token = document.querySelector('meta[name="csrf-token"]');
if (token && (token instanceof window.HTMLMetaElement)) {
return token.content;
}
return null;
},

authenticityHeaders(otherHeaders: {[id:string]: string} = {}) {
authenticityHeaders(otherHeaders: {[id: string]: string} = {}): AuthenticityHeaders {
return Object.assign(otherHeaders, {
'X-CSRF-Token': this.authenticityToken(),
'X-Requested-With': 'XMLHttpRequest',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// key = name used by react_on_rails
// value = { name, component, generatorFunction: boolean, isRenderer: boolean }
import type { RegisteredComponent, ComponentOrRenderFunction, RenderFunction } from './types/index';
import generatorFunction from './generatorFunction';

const registeredComponents = new Map();
Expand All @@ -8,7 +7,7 @@ export default {
/**
* @param components { component1: component1, component2: component2, etc. }
*/
register(components) {
register(components: { [id: string]: ComponentOrRenderFunction }): void {
Object.keys(components).forEach(name => {
if (registeredComponents.has(name)) {
console.warn('Called register for component that is already registered', name);
Expand All @@ -20,7 +19,7 @@ export default {
}

const isGeneratorFunction = generatorFunction(component);
const isRenderer = isGeneratorFunction && component.length === 3;
const isRenderer = isGeneratorFunction && (component as RenderFunction).length === 3;

registeredComponents.set(name, {
name,
Expand All @@ -33,9 +32,9 @@ export default {

/**
* @param name
* @returns { name, component, generatorFunction }
* @returns { name, component, generatorFunction, isRenderer }
*/
get(name) {
get(name: string): RegisteredComponent {
if (registeredComponents.has(name)) {
return registeredComponents.get(name);
}
Expand All @@ -48,9 +47,9 @@ Registered component names include [ ${keys} ]. Maybe you forgot to register the
/**
* Get a Map containing all registered components. Useful for debugging.
* @returns Map where key is the component name and values are the
* { name, component, generatorFunction}
* { name, component, generatorFunction, isRenderer}
*/
components() {
components(): Map<string, RegisteredComponent> {
return registeredComponents;
},
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import ReactDOM from 'react-dom';
import type { ReactElement, Component } from 'react';
import type { Store } from 'redux';

import * as ClientStartup from './clientStartup';
import handleError from './handleError';
Expand All @@ -9,20 +11,33 @@ import buildConsoleReplay from './buildConsoleReplay';
import createReactElement from './createReactElement';
import Authenticity from './Authenticity';
import context from './context';
import type {
RegisteredComponent,
RenderParams,
ErrorOptions,
ComponentOrRenderFunction,
AuthenticityHeaders,
StoreGenerator
} from './types/index';

const ctx = context();

if (ctx === undefined) {
throw new Error("The context (usually Window or NodeJS's Global) is undefined.");
}

const DEFAULT_OPTIONS = {
traceTurbolinks: false,
};

ctx.ReactOnRails = {
options: {},
/**
* Main entry point to using the react-on-rails npm package. This is how Rails will be able to
* find you components for rendering.
* @param components (key is component name, value is component)
*/
register(components) {
register(components: { [id: string]: ComponentOrRenderFunction }): void {
ComponentRegistry.register(components);
},

Expand All @@ -32,7 +47,7 @@ ctx.ReactOnRails = {
* the setStore API is different in that it's the actual store hydrated with props.
* @param stores (keys are store names, values are the store generators)
*/
registerStore(stores) {
registerStore(stores: { [id: string]: Store }): void {
if (!stores) {
throw new Error('Called ReactOnRails.registerStores with a null or undefined, rather than ' +
'an Object with keys being the store names and the values are the store generators.');
Expand All @@ -50,7 +65,7 @@ ctx.ReactOnRails = {
* there is no store with the given name.
* @returns Redux Store, possibly hydrated
*/
getStore(name, throwIfMissing = true) {
getStore(name: string, throwIfMissing = true): Store | undefined {
return StoreRegistry.getStore(name, throwIfMissing);
},

Expand All @@ -59,7 +74,7 @@ ctx.ReactOnRails = {
* Available Options:
* `traceTurbolinks: true|false Gives you debugging messages on Turbolinks events
*/
setOptions(newOptions) {
setOptions(newOptions: {traceTurbolinks: boolean}): void {
if ('traceTurbolinks' in newOptions) {
this.options.traceTurbolinks = newOptions.traceTurbolinks;

Expand All @@ -69,7 +84,7 @@ ctx.ReactOnRails = {

if (Object.keys(newOptions).length > 0) {
throw new Error(
'Invalid options passed to ReactOnRails.options: ', JSON.stringify(newOptions),
`Invalid options passed to ReactOnRails.options: ${JSON.stringify(newOptions)}`,
);
}
},
Expand All @@ -80,7 +95,7 @@ ctx.ReactOnRails = {
* More details can be found here:
* https://github.com/shakacode/react_on_rails/blob/master/docs/additional-reading/turbolinks.md
*/
reactOnRailsPageLoaded() {
reactOnRailsPageLoaded(): void {
ClientStartup.reactOnRailsPageLoaded();
},

Expand All @@ -89,7 +104,7 @@ ctx.ReactOnRails = {
* @returns String or null
*/

authenticityToken() {
authenticityToken(): string | null {
return Authenticity.authenticityToken();
},

Expand All @@ -99,7 +114,7 @@ ctx.ReactOnRails = {
* @returns {*} header
*/

authenticityHeaders(otherHeaders = {}) {
authenticityHeaders(otherHeaders: { [id: string]: string } = {}): AuthenticityHeaders {
return Authenticity.authenticityHeaders(otherHeaders);
},

Expand All @@ -112,7 +127,7 @@ ctx.ReactOnRails = {
* @param key
* @returns option value
*/
option(key) {
option(key: string): string | number | boolean | undefined {
return this.options[key];
},

Expand All @@ -122,7 +137,7 @@ ctx.ReactOnRails = {
* @param name
* @returns Redux Store generator function
*/
getStoreGenerator(name) {
getStoreGenerator(name: string): StoreGenerator {
return StoreRegistry.getStoreGenerator(name);
},

Expand All @@ -131,15 +146,15 @@ ctx.ReactOnRails = {
* @param name
* @returns Redux Store, possibly hydrated
*/
setStore(name, store) {
setStore(name: string, store: Store): void {
return StoreRegistry.setStore(name, store);
},

/**
* Clears hydratedStores to avoid accidental usage of wrong store hydrated in previous/parallel
* request.
*/
clearHydratedStores() {
clearHydratedStores(): void {
StoreRegistry.clearHydratedStores();
},

Expand All @@ -156,72 +171,72 @@ ctx.ReactOnRails = {
* @param hydrate Pass truthy to update server rendered html. Default is falsy
* @returns {virtualDomElement} Reference to your component's backing instance
*/
render(name, props, domNodeId, hydrate) {
render(name: string, props: Record<string, string>, domNodeId: string, hydrate: boolean): void | Element | Component {
const componentObj = ComponentRegistry.get(name);
const reactElement = createReactElement({ componentObj, props, domNodeId });

const render = hydrate ? ReactDOM.hydrate : ReactDOM.render;
// eslint-disable-next-line react/no-render-return-value
return render(reactElement, document.getElementById(domNodeId));
return render(reactElement as ReactElement, document.getElementById(domNodeId));
},

/**
* Get the component that you registered
* @param name
* @returns {name, component, generatorFunction, isRenderer}
*/
getComponent(name) {
getComponent(name: string): RegisteredComponent {
return ComponentRegistry.get(name);
},

/**
* Used by server rendering by Rails
* @param options
*/
serverRenderReactComponent(options) {
serverRenderReactComponent(options: RenderParams): string {
return serverRenderReactComponent(options);
},

/**
* Used by Rails to catch errors in rendering
* @param options
*/
handleError(options) {
handleError(options: ErrorOptions): string | undefined {
return handleError(options);
},

/**
* Used by Rails server rendering to replay console messages.
*/
buildConsoleReplay() {
buildConsoleReplay(): string {
return buildConsoleReplay();
},

/**
* Get an Object containing all registered components. Useful for debugging.
* @returns {*}
*/
registeredComponents() {
registeredComponents(): Map<string, RegisteredComponent> {
return ComponentRegistry.components();
},

/**
* Get an Object containing all registered store generators. Useful for debugging.
* @returns {*}
*/
storeGenerators() {
storeGenerators(): Map<string, Function> {
return StoreRegistry.storeGenerators();
},

/**
* Get an Object containing all hydrated stores. Useful for debugging.
* @returns {*}
*/
stores() {
stores(): Map<string, Store> {
return StoreRegistry.stores();
},

resetOptions() {
resetOptions(): void {
this.options = Object.assign({}, DEFAULT_OPTIONS);
},
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export default {
wrapInScriptTags(scriptId, scriptBody) {
wrapInScriptTags(scriptId: string, scriptBody: string): string {
if (!scriptBody) {
return '';
}
Expand Down
Loading

0 comments on commit 121af31

Please sign in to comment.