Skip to content

Commit 121af31

Browse files
authored
Switch Node_Package from Flow to Typescript (#1250)
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
1 parent 2b5c313 commit 121af31

35 files changed

+3272
-1231
lines changed

.eslintrc

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,38 @@ env:
1515
browser: true
1616
node: true
1717
mocha: true
18+
jest: true
19+
20+
overrides:
21+
- files: ["**/*.ts", "**/*.tsx"]
22+
parser: "@typescript-eslint/parser"
23+
parserOptions:
24+
ecmaVersion: 2018
25+
sourceType: module
26+
project: "./tsconfig.json"
27+
extends:
28+
- eslint:recommended
29+
- plugin:@typescript-eslint/eslint-recommended
30+
- plugin:@typescript-eslint/recommended
31+
plugins:
32+
- "@typescript-eslint"
33+
rules:
34+
"@typescript-eslint/no-namespace": 0
1835

1936
rules:
2037
no-console: 0
2138
function-paren-newline: 0
2239
object-curly-newline: 0
2340

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

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

2847
settings:
2948
import/core-modules:
3049
- react-redux
50+
import/resolver:
51+
node:
52+
extensions: [".js", ".ts", ".d.ts"]

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ before_install:
3535

3636
install:
3737
- travis_retry gem install bundler -v '>2'
38-
- travis_retry nvm install 10.13.0
38+
- travis_retry nvm install 13.9.0
3939
- node -v
4040
- travis_retry npm i -g yarn
4141
- travis_retry bundle install

jest.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
preset: 'ts-jest/presets/js-with-ts',
3+
testEnvironment: 'jsdom',
4+
};

node_package/.babelrc

Lines changed: 0 additions & 10 deletions
This file was deleted.

node_package/.flowconfig

Lines changed: 0 additions & 3 deletions
This file was deleted.

node_package/src/Authenticity.js renamed to node_package/src/Authenticity.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
// @flow
1+
import type { AuthenticityHeaders } from './types/index';
22

33
export default {
4-
5-
authenticityToken() {
6-
const token: ?HTMLElement = document.querySelector('meta[name="csrf-token"]');
4+
authenticityToken(): string | null {
5+
const token = document.querySelector('meta[name="csrf-token"]');
76
if (token && (token instanceof window.HTMLMetaElement)) {
87
return token.content;
98
}
109
return null;
1110
},
1211

13-
authenticityHeaders(otherHeaders: {[id:string]: string} = {}) {
12+
authenticityHeaders(otherHeaders: {[id: string]: string} = {}): AuthenticityHeaders {
1413
return Object.assign(otherHeaders, {
1514
'X-CSRF-Token': this.authenticityToken(),
1615
'X-Requested-With': 'XMLHttpRequest',

node_package/src/ComponentRegistry.js renamed to node_package/src/ComponentRegistry.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// key = name used by react_on_rails
2-
// value = { name, component, generatorFunction: boolean, isRenderer: boolean }
1+
import type { RegisteredComponent, ComponentOrRenderFunction, RenderFunction } from './types/index';
32
import generatorFunction from './generatorFunction';
43

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

2221
const isGeneratorFunction = generatorFunction(component);
23-
const isRenderer = isGeneratorFunction && component.length === 3;
22+
const isRenderer = isGeneratorFunction && (component as RenderFunction).length === 3;
2423

2524
registeredComponents.set(name, {
2625
name,
@@ -33,9 +32,9 @@ export default {
3332

3433
/**
3534
* @param name
36-
* @returns { name, component, generatorFunction }
35+
* @returns { name, component, generatorFunction, isRenderer }
3736
*/
38-
get(name) {
37+
get(name: string): RegisteredComponent {
3938
if (registeredComponents.has(name)) {
4039
return registeredComponents.get(name);
4140
}
@@ -48,9 +47,9 @@ Registered component names include [ ${keys} ]. Maybe you forgot to register the
4847
/**
4948
* Get a Map containing all registered components. Useful for debugging.
5049
* @returns Map where key is the component name and values are the
51-
* { name, component, generatorFunction}
50+
* { name, component, generatorFunction, isRenderer}
5251
*/
53-
components() {
52+
components(): Map<string, RegisteredComponent> {
5453
return registeredComponents;
5554
},
5655
};

node_package/src/ReactOnRails.js renamed to node_package/src/ReactOnRails.ts

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import ReactDOM from 'react-dom';
2+
import type { ReactElement, Component } from 'react';
3+
import type { Store } from 'redux';
24

35
import * as ClientStartup from './clientStartup';
46
import handleError from './handleError';
@@ -9,20 +11,33 @@ import buildConsoleReplay from './buildConsoleReplay';
911
import createReactElement from './createReactElement';
1012
import Authenticity from './Authenticity';
1113
import context from './context';
14+
import type {
15+
RegisteredComponent,
16+
RenderParams,
17+
ErrorOptions,
18+
ComponentOrRenderFunction,
19+
AuthenticityHeaders,
20+
StoreGenerator
21+
} from './types/index';
1222

1323
const ctx = context();
1424

25+
if (ctx === undefined) {
26+
throw new Error("The context (usually Window or NodeJS's Global) is undefined.");
27+
}
28+
1529
const DEFAULT_OPTIONS = {
1630
traceTurbolinks: false,
1731
};
1832

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

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

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

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

7085
if (Object.keys(newOptions).length > 0) {
7186
throw new Error(
72-
'Invalid options passed to ReactOnRails.options: ', JSON.stringify(newOptions),
87+
`Invalid options passed to ReactOnRails.options: ${JSON.stringify(newOptions)}`,
7388
);
7489
}
7590
},
@@ -80,7 +95,7 @@ ctx.ReactOnRails = {
8095
* More details can be found here:
8196
* https://github.com/shakacode/react_on_rails/blob/master/docs/additional-reading/turbolinks.md
8297
*/
83-
reactOnRailsPageLoaded() {
98+
reactOnRailsPageLoaded(): void {
8499
ClientStartup.reactOnRailsPageLoaded();
85100
},
86101

@@ -89,7 +104,7 @@ ctx.ReactOnRails = {
89104
* @returns String or null
90105
*/
91106

92-
authenticityToken() {
107+
authenticityToken(): string | null {
93108
return Authenticity.authenticityToken();
94109
},
95110

@@ -99,7 +114,7 @@ ctx.ReactOnRails = {
99114
* @returns {*} header
100115
*/
101116

102-
authenticityHeaders(otherHeaders = {}) {
117+
authenticityHeaders(otherHeaders: { [id: string]: string } = {}): AuthenticityHeaders {
103118
return Authenticity.authenticityHeaders(otherHeaders);
104119
},
105120

@@ -112,7 +127,7 @@ ctx.ReactOnRails = {
112127
* @param key
113128
* @returns option value
114129
*/
115-
option(key) {
130+
option(key: string): string | number | boolean | undefined {
116131
return this.options[key];
117132
},
118133

@@ -122,7 +137,7 @@ ctx.ReactOnRails = {
122137
* @param name
123138
* @returns Redux Store generator function
124139
*/
125-
getStoreGenerator(name) {
140+
getStoreGenerator(name: string): StoreGenerator {
126141
return StoreRegistry.getStoreGenerator(name);
127142
},
128143

@@ -131,15 +146,15 @@ ctx.ReactOnRails = {
131146
* @param name
132147
* @returns Redux Store, possibly hydrated
133148
*/
134-
setStore(name, store) {
149+
setStore(name: string, store: Store): void {
135150
return StoreRegistry.setStore(name, store);
136151
},
137152

138153
/**
139154
* Clears hydratedStores to avoid accidental usage of wrong store hydrated in previous/parallel
140155
* request.
141156
*/
142-
clearHydratedStores() {
157+
clearHydratedStores(): void {
143158
StoreRegistry.clearHydratedStores();
144159
},
145160

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

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

168183
/**
169184
* Get the component that you registered
170185
* @param name
171186
* @returns {name, component, generatorFunction, isRenderer}
172187
*/
173-
getComponent(name) {
188+
getComponent(name: string): RegisteredComponent {
174189
return ComponentRegistry.get(name);
175190
},
176191

177192
/**
178193
* Used by server rendering by Rails
179194
* @param options
180195
*/
181-
serverRenderReactComponent(options) {
196+
serverRenderReactComponent(options: RenderParams): string {
182197
return serverRenderReactComponent(options);
183198
},
184199

185200
/**
186201
* Used by Rails to catch errors in rendering
187202
* @param options
188203
*/
189-
handleError(options) {
204+
handleError(options: ErrorOptions): string | undefined {
190205
return handleError(options);
191206
},
192207

193208
/**
194209
* Used by Rails server rendering to replay console messages.
195210
*/
196-
buildConsoleReplay() {
211+
buildConsoleReplay(): string {
197212
return buildConsoleReplay();
198213
},
199214

200215
/**
201216
* Get an Object containing all registered components. Useful for debugging.
202217
* @returns {*}
203218
*/
204-
registeredComponents() {
219+
registeredComponents(): Map<string, RegisteredComponent> {
205220
return ComponentRegistry.components();
206221
},
207222

208223
/**
209224
* Get an Object containing all registered store generators. Useful for debugging.
210225
* @returns {*}
211226
*/
212-
storeGenerators() {
227+
storeGenerators(): Map<string, Function> {
213228
return StoreRegistry.storeGenerators();
214229
},
215230

216231
/**
217232
* Get an Object containing all hydrated stores. Useful for debugging.
218233
* @returns {*}
219234
*/
220-
stores() {
235+
stores(): Map<string, Store> {
221236
return StoreRegistry.stores();
222237
},
223238

224-
resetOptions() {
239+
resetOptions(): void {
225240
this.options = Object.assign({}, DEFAULT_OPTIONS);
226241
},
227242
};

node_package/src/RenderUtils.js renamed to node_package/src/RenderUtils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export default {
2-
wrapInScriptTags(scriptId, scriptBody) {
2+
wrapInScriptTags(scriptId: string, scriptBody: string): string {
33
if (!scriptBody) {
44
return '';
55
}

0 commit comments

Comments
 (0)