Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@finsemble/finsemble-ui

Package Overview
Dependencies
Maintainers
1
Versions
303
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@finsemble/finsemble-ui

The Finsemble UI API and assorted building blocks to make good looking, smooth running SmartDesktops.

  • 5.0.0-beta.2
  • npm
  • Socket score

Version published
Weekly downloads
752
increased by113.64%
Maintainers
1
Weekly downloads
 
Created
Source

Finsemble UI

Project Requirements

Build Requirements

  1. The library shall be delivered as a single NPM package.
  2. The library shall be usable as either a typescript or a javascript library.

Typescript Requirements

  1. The library shall be compiled in strict mode (see &sa=D&ust=1581539948628000)https://www.typescriptlang.org/docs/handbook/compiler-options.html)&sa=D&ust=1581539948628000)
  2. The library shall use optional chaining and null coalescense for optional property access.
    • The lib shall not use lodash.set and get, && chaining, or ternary operators to accomplish this purpose.
  3. All types shall be as precise and accurate as reasonable.
    • The any type shall not be used whenever a more accurate type is known.
    • Prefer generics over any. For example:
function map(cb: (el: T1) => T2, array: T1[]): T2[] {
	//...
}
  • There are places where the type cannot be known, or the function's output does not depend on the type input. A prime example is logging.
function log(...args: any[]): void { ... }
  • All nullable types shall be designated as such with the ? suffix or with | undefined.

For example:

// Incorrect example
const foo: Record = { bar: 7 };
foo.quux; // type is number, but value is undefined!

// Correct example
const foo: Record = { bar: 7 };
foo.quux; // type is (number | undefined), which is correct

Whenever Typescript cannot infer the correct type, you may use casting if you are absolutely sure of the correct type. For example, the following is allowed:

const foo: Record = {bar: 7}
const bar = Object.values(foo) as number[];

Component Requirements

  1. All React Components shall be functions (as opposed to classes).
  2. For simple, one-off cases, the component code may directly call Finsemble clients from within a useEffect hook, bypassing the effects API and Redux infrastructure. (These should be the exception, not the rule)
  3. All component state is captured either in the Redux Store or in useState hooks. The following guidelines determine which one:
    • useState may be used only if that state is not passed down to child components, shared with other peer components, OR if child components are only "dumb components" (see https://alligator.io/react/smart-dumb-components/ for definition of smart vs. dumb components)
    • In all other cases, use the Store.
  4. Prefer Context API over "prop drilling" (deep prop-passing hierarchies)

Redux Requirements

  1. All reducer functions shall be pure functions (free from all side effects, including logging, network requests, etc.).
  2. The library shall use Immer to create immutable redux values with a mutable API.
  1. Reducers shall be typesafe from end to end.
  2. Actions shall be specified using the Unionize library. Actions shall be created for dispatch using Unionize's factory functions.
  3. Logging shall be achieved by a single, top level meta-reducer (a.k.a middleware)
  4. Actions are namespaced. E.g. "Linker Menu/Toggle Linker"
  5. In development mode, the library shall use the Redux-DevTools for diagnostics.
  1. The store shall be normalized according to the guidelines here: https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape/

Hooks Requirements

  1. The only internal dependency of the hooks code shall be the action factories created with Unionize and the effects code.
  2. All side effects (including Finsemble client calls and action dispatch) shall be exported as React Hooks based on useEffect.
  3. Because the hooks serve as the public API of the library, all hook code shall be thoroughly documented with JSDoc strings.
  4. As much as possible, the library shall relegate conditional logic to the reducer, keeping the hook code condition-free.
    • The rationale: Reducers are pure functions. Pure functions are easy to reason about, write, and test. Conditionals are hard (if(menuIsOpen && !menuIsException && config.autoClose gets really tricky really fast). Keeping them in pure functions makes them less hard.

Testing Requirements and Guidelines

The following policies are experimental. Give them a shot - but if you find they can be improved, talk to the chief architect.

The guiding principle is that conditional business logic (anything with if or switch statement that depends on domain knowledge), should have tests, because unit tests are an excellent development tool, aide in understanding the code, and can prevent regressions. In general, conditional business logic should be relegated to the reducer functions; however, if this proves too difficult, exceptions can be made in the hooks.

  1. Every reducer shall have 100% test coverage via unit tests.
  2. Component code is not required to have testing coverage. React encourages building complex UI's from smaller, simpler one's, and if you find a particular component is getting difficult to understand, consider refactoring.
  3. Effect code is not required to have test coverage. For the most part, effect functions should not contain conditional business logic - instead, push the logic up into the reducers or hooks (preferably the reducers).
  4. Hook code is not required to have test coverage. Prefer to keep conditional business logic inside the reducer when possible. If this proves too cumbersome, consider extracting the logic into a pure function that maps a paritcular state and input to the desired effect, and test that function. Prefer functional programming techniques over mocking. For example the:
// Bad example - conditional code is mixed in with Finsemble service calls.
const useFoo = () => {
	...
	if(!state.foo.ignoreBar && state.foo.bar > state.baz) {
		await FSBL.FooClient.doFoo(foo, "start")
	} else {
		await FSBL.FooClient.cancelFoo(foo);
	}
	...
}
// Better example - Conditional code is encapsultaed in pure function.
const doFoo (foo: Foo) => await FSBL.FooClient.doFoo(foo, "start");
const cancelFoo (foo: Foo) => await FSBL.FooClient.cancelFoo(foo);

// Because this is a pure function (returns a function reference but doesn't invoke),
// it's easily testable.
const decideFoo = (foo) => {
	return (!state.foo.ignoreBar && state.foo.bar > state.baz)
		? doFoo : cancelFoo;
}

const useFoo = () => {
	...
	decideFoo(foo)();
	...
}

Dan Abramov's post on setTimeout and useRef https://overreacted.io/making-setinterval-declarative-with-react-hooks/

Dan Abramov's comments on React portals https://github.com/facebook/react/issues/12355#issuecomment-410996235

FAQs

Package last updated on 03 Sep 2020

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc