Skip to content

Commit

Permalink
v1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
stackptr committed Mar 10, 2023
1 parent a466960 commit 769ace5
Show file tree
Hide file tree
Showing 16 changed files with 423 additions and 56 deletions.
90 changes: 78 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,93 @@
# npm Package Template
# Resource Status

Our custom template repository for creating a package published to npm.

[Creating a repository from a template][docs].

[docs]: https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template

**NOTE**: Be sure to look for strings like "TODO", "Package name", or "package-name" and update
them accordingly.
Defines the `ResourceStatusT` type and utilities operating on this type.

## Install

```sh
yarn add package-name
yarn add @freckle/resource-status
```

## Versioning and release process

See [RELEASE.md](./RELEASE.md).

## process(input)
## `ResourceStatusT<R>`

Wraps data from a resource `R` with metadata to describe the status of accessing
and updating the data. The `status` field can be used to react accordingly:

```ts
type Props = {resource: ResourceStatusT<{username: string}>}
const UserView = ({resource}: Props) => {
switch (resource.status) {
case 'idle':
return <p>User has not been loaded</p>
case 'loading':
return <p>Loading user</p>
case 'reloading':
return <p>User: {resource.data.username} (reloading)</p>
case 'error':
return (
<p>
Error loading user: <pre>{JSON.stringify(resource.error)}</pre>
</p>
)
case 'complete':
return <p>User: {resource.data.username}</p>
case 'updating':
return <p>User: {resource.data.username} (pending update)</p>
case 'updating-error':
return (
<p>
Error updating user {resource.data.username}: <pre>{JSON.stringify(resource.error)}</pre>
</p>
)
default:
return exhaustive(resource)
}
}
```

## Utilities

Utilities are defined to make operating on a resource status.

### `maybeResourceData(resource)`

TODO: Document public API for package.
Returns the underlying `resource.data` if it exists.

### `fromMaybeResourceData(resource, default)`

Returns the underlying `resource.data` if it exists, or `default` otherwise.

### `isFetching(resource)`

Returns `true` when a `resource` is loading or reloading.

### `updateResource(resource, updateFn)`

Performs `updateFn(resource.data)` if there exists data in the resource, and
returns a new `resource`. This is convenient for reducer-style updates:

```ts
type State = ResourceStatusT<{username: string; token: string}>
type Action =
| {type: 'USER_UPDATE_REQUEST'}
| {type: 'USER_UPDATE_RESPONSE'; data: {username: string}}

const reducer = (state: State, action: Action) => {
switch (action.type) {
case 'USER_UPDATE_REQUEST':
// ...
case 'USER_UPDATE_RESPONSE':
return updateResource(state, user => ({
...user,
username: action.data.username
}))
}
}
```

---

Expand Down
3 changes: 2 additions & 1 deletion dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { process } from './process';
export type { ResourceStatusT } from './resource-status';
export { fromMaybeResourceData, maybeResourceData, isFetching, updateResource } from './resource-status';
9 changes: 6 additions & 3 deletions dist/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.process = void 0;
var process_1 = require("./process");
Object.defineProperty(exports, "process", { enumerable: true, get: function () { return process_1.process; } });
exports.updateResource = exports.isFetching = exports.maybeResourceData = exports.fromMaybeResourceData = void 0;
var resource_status_1 = require("./resource-status");
Object.defineProperty(exports, "fromMaybeResourceData", { enumerable: true, get: function () { return resource_status_1.fromMaybeResourceData; } });
Object.defineProperty(exports, "maybeResourceData", { enumerable: true, get: function () { return resource_status_1.maybeResourceData; } });
Object.defineProperty(exports, "isFetching", { enumerable: true, get: function () { return resource_status_1.isFetching; } });
Object.defineProperty(exports, "updateResource", { enumerable: true, get: function () { return resource_status_1.updateResource; } });
8 changes: 7 additions & 1 deletion dist/index.js.flow
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
// @flow
declare export { process } from "./process";
export type { ResourceStatusT } from "./resource-status";
declare export {
fromMaybeResourceData,
maybeResourceData,
isFetching,
updateResource,
} from "./resource-status";
4 changes: 0 additions & 4 deletions dist/process.d.ts

This file was deleted.

9 changes: 0 additions & 9 deletions dist/process.js

This file was deleted.

5 changes: 0 additions & 5 deletions dist/process.js.flow

This file was deleted.

26 changes: 26 additions & 0 deletions dist/resource-status.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export type ResourceStatusT<R> = {
status: 'idle';
} | {
status: 'loading';
} | {
status: 'reloading';
data: R;
} | {
status: 'error';
error: unknown;
} | {
status: 'complete';
data: R;
hasUpdated: boolean;
} | {
status: 'updating';
data: R;
} | {
status: 'updating-error';
data: R;
error: unknown;
};
export declare function fromMaybeResourceData<R>(resource: ResourceStatusT<R>, defaultData: R): R;
export declare function maybeResourceData<R>(resource: ResourceStatusT<R>): R | undefined | null;
export declare function isFetching<R>(resource: ResourceStatusT<R>): boolean;
export declare const updateResource: <R>(resource: ResourceStatusT<R>, update: (data: R) => R) => ResourceStatusT<R>;
44 changes: 44 additions & 0 deletions dist/resource-status.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateResource = exports.isFetching = exports.maybeResourceData = exports.fromMaybeResourceData = void 0;
const maybe_1 = require("@freckle/maybe");
const exhaustive_js_1 = require("@freckle/exhaustive-js");
function fromMaybeResourceData(resource, defaultData) {
var _a;
return (_a = maybeResourceData(resource)) !== null && _a !== void 0 ? _a : defaultData;
}
exports.fromMaybeResourceData = fromMaybeResourceData;
function maybeResourceData(resource) {
switch (resource.status) {
case 'idle':
return null;
case 'loading':
return null;
case 'reloading':
return resource.data;
case 'error':
return null;
case 'complete':
return resource.data;
case 'updating':
return resource.data;
case 'updating-error':
return resource.data;
default:
return (0, exhaustive_js_1.exhaustive)(resource);
}
}
exports.maybeResourceData = maybeResourceData;
function isFetching(resource) {
return resource.status === 'loading' || resource.status === 'reloading';
}
exports.isFetching = isFetching;
const updateResource = (resource, update) => {
const mData = maybeResourceData(resource);
return (0, maybe_1.maybe)(() => resource, data => ({
status: 'complete',
data: update(data),
hasUpdated: false // This is used for async updates, e.g. from a fetch response
}), mData);
};
exports.updateResource = updateResource;
42 changes: 42 additions & 0 deletions dist/resource-status.js.flow
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// @flow
export type ResourceStatusT<R> =
| {|
status: "idle",
|}
| {|
status: "loading",
|}
| {|
status: "reloading",
data: R,
|}
| {|
status: "error",
error: mixed,
|}
| {|
status: "complete",
data: R,
hasUpdated: boolean,
|}
| {|
status: "updating",
data: R,
|}
| {|
status: "updating-error",
data: R,
error: mixed,
|};
declare export function fromMaybeResourceData<R>(
resource: ResourceStatusT<R>,
defaultData: R
): R;
declare export function maybeResourceData<R>(
resource: ResourceStatusT<R>
): R | void | null;
declare export function isFetching<R>(resource: ResourceStatusT<R>): boolean;
declare export var updateResource: <R>(
resource: ResourceStatusT<R>,
update: (data: R) => R
) => ResourceStatusT<R>;
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
{
"name": "@freckle/package-name",
"name": "@freckle/resource-status",
"version": "1.0.0",
"description": "TODO: Package description",
"description": "ResourceStatusT type and utilities",
"author": "Freckle",
"license": "MIT",
"main": "./dist/index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/freckle/package-name-js.git"
"url": "git+https://github.com/freckle/resource-status-js.git"
},
"scripts": {
"build": "rm -r dist && tsc -d && node gen-flow.js",
"test": "jest && flow",
"format": "prettier --write 'src/**/*.ts'"
},
"dependencies": {
"lodash": "^4.17.21"
"@freckle/exhaustive-js": "https://github.com/freckle/exhaustive-js.git#v1.0.0",
"@freckle/maybe": "https://github.com/freckle/maybe-js.git#v2.2.0"
},
"devDependencies": {
"@types/jest": "^28.1.1",
Expand Down
Loading

0 comments on commit 769ace5

Please sign in to comment.