Merge pull request #2733 from sanderhahn/master

typescript version of store
pull/2782/head
Rich Harris 5 years ago committed by GitHub
commit 8d539d8e55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

2
.gitignore vendored

@ -6,7 +6,7 @@ node_modules
/compiler.js
/index.js
/internal.*
/store.js
/store.*
/easing.js
/motion.*
/transition.js

@ -27,11 +27,12 @@
"precodecov": "npm run coverage",
"lint": "eslint src test/*.js",
"build": "rollup -c",
"prepare": "npm run build",
"prepare": "npm run build && npm run tsd",
"dev": "rollup -cw",
"pretest": "npm run build",
"posttest": "agadoo src/internal/index.js",
"prepublishOnly": "export PUBLISH=true && npm run lint && npm test"
"prepublishOnly": "export PUBLISH=true && npm run lint && npm test",
"tsd": "tsc -d src/store.ts --outDir ."
},
"repository": {
"type": "git",

@ -87,8 +87,37 @@ export default [
external: id => id.startsWith('svelte/')
},
/* store.mjs */
{
input: `src/store.ts`,
output: [
{
file: `store.mjs`,
format: 'esm',
paths: id => id.startsWith('svelte/') && id.replace('svelte', '.')
},
{
file: `store.js`,
format: 'cjs',
paths: id => id.startsWith('svelte/') && id.replace('svelte', '.')
}
],
plugins: [
is_publish
? typescript({
include: 'src/**',
exclude: 'src/internal/**',
typescript: require('typescript')
})
: sucrase({
transforms: ['typescript']
})
],
external: id => id.startsWith('svelte/')
},
// everything else
...['index', 'store', 'easing', 'transition', 'animate'].map(name => ({
...['index', 'easing', 'transition', 'animate'].map(name => ({
input: `${name}.mjs`,
output: {
file: `${name}.js`,

@ -0,0 +1,136 @@
import { run_all, noop, safe_not_equal } from './internal/utils';
type Subscriber<T> = (value: T) => void;
type Unsubscriber = () => void;
type Updater<T> = (value: T) => T;
type Invalidater<T> = (value?: T) => void;
type StartStopNotifier<T> = (set: Subscriber<T>) => Unsubscriber | void;
export interface Readable<T> {
subscribe(run: Subscriber<T>, invalidate?: Invalidater<T>): Unsubscriber;
}
export interface Writable<T> extends Readable<T> {
set(value: T): void;
update(updater: Updater<T>): void;
}
type SubscribeInvalidateTuple<T> = [Subscriber<T>, Invalidater<T>];
export function readable<T>(value: T, start: StartStopNotifier<T>): Readable<T> {
return {
subscribe: writable(value, start).subscribe,
};
}
export function writable<T>(value: T, start: StartStopNotifier<T> = noop): Writable<T> {
let stop: Unsubscriber;
const subscribers: Array<SubscribeInvalidateTuple<T>> = [];
function set(new_value: T): void {
if (safe_not_equal(value, new_value)) {
value = new_value;
if (!stop) {
return; // not ready
}
subscribers.forEach((s) => s[1]());
subscribers.forEach((s) => s[0](value));
}
}
function update(fn: Updater<T>): void {
set(fn(value));
}
function subscribe(run: Subscriber<T>, invalidate: Invalidater<T> = noop): Unsubscriber {
const subscriber: SubscribeInvalidateTuple<T> = [run, invalidate];
subscribers.push(subscriber);
if (subscribers.length === 1) {
stop = start(set) || noop;
}
run(value);
return () => {
const index = subscribers.indexOf(subscriber);
if (index !== -1) {
subscribers.splice(index, 1);
}
if (subscribers.length === 0) {
stop();
}
};
}
return { set, update, subscribe };
}
type Stores = Readable<any> | [Readable<any>, ...Array<Readable<any>>];
type StoresValues<T> = T extends Readable<infer U> ? U :
{ [K in keyof T]: T[K] extends Readable<infer U> ? U : never };
export function derived<T, S extends Stores>(
stores: S,
fn: (values: StoresValues<S>, set?: Subscriber<T>) => T | Unsubscriber | void,
initial_value?: T,
): Readable<T> {
const single = !Array.isArray(stores);
const stores_array: Array<Readable<any>> = single
? [stores as Readable<any>]
: stores as Array<Readable<any>>;
const auto = fn.length < 2;
return readable(initial_value, (set) => {
let inited = false;
const values: StoresValues<S> = [] as StoresValues<S>;
let pending = 0;
let cleanup = noop;
const sync = () => {
if (pending) {
return;
}
cleanup();
const result = fn(single ? values[0] : values, set);
if (auto) {
set(result as T);
} else {
cleanup = result as Unsubscriber || noop;
}
};
const unsubscribers = stores_array.map((store, i) => store.subscribe(
(value) => {
values[i] = value;
pending &= ~(1 << i);
if (inited) {
sync();
}
},
() => {
pending |= (1 << i);
}),
);
inited = true;
sync();
return function stop() {
run_all(unsubscribers);
cleanup();
};
});
}
export function get<T>(store: Readable<T>): T {
let value: T | undefined;
store.subscribe((_: T) => value = _)();
return value as T;
}

@ -1,85 +0,0 @@
import { run_all, noop, get_store_value, safe_not_equal } from './internal';
export function readable(value, start) {
return {
subscribe: writable(value, start).subscribe
};
}
export function writable(value, start = noop) {
let stop;
const subscribers = [];
function set(new_value) {
if (safe_not_equal(value, new_value)) {
value = new_value;
if (!stop) return; // not ready
subscribers.forEach(s => s[1]());
subscribers.forEach(s => s[0](value));
}
}
function update(fn) {
set(fn(value));
}
function subscribe(run, invalidate = noop) {
const subscriber = [run, invalidate];
subscribers.push(subscriber);
if (subscribers.length === 1) stop = start(set) || noop;
run(value);
return () => {
const index = subscribers.indexOf(subscriber);
if (index !== -1) subscribers.splice(index, 1);
if (subscribers.length === 0) stop();
};
}
return { set, update, subscribe };
}
export function derived(stores, fn, initial_value) {
const single = !Array.isArray(stores);
if (single) stores = [stores];
const auto = fn.length < 2;
let value = {};
return readable(initial_value, set => {
let inited = false;
const values = [];
let pending = 0;
let cleanup = noop;
const sync = () => {
if (pending) return;
cleanup();
const result = fn(single ? values[0] : values, set);
if (auto) set(result);
else cleanup = result || noop;
};
const unsubscribers = stores.map((store, i) => store.subscribe(
value => {
values[i] = value;
pending &= ~(1 << i);
if (inited) sync();
},
() => {
pending |= (1 << i);
})
);
inited = true;
sync();
return function stop() {
run_all(unsubscribers);
cleanup();
};
});
}
export { get_store_value as get };

@ -1,5 +1,5 @@
import * as assert from 'assert';
import { readable, writable, derived, get } from '../../store.js';
import { readable, writable, derived, get } from '../store';
describe('store', () => {
describe('writable', () => {
@ -30,10 +30,10 @@ describe('store', () => {
return () => called -= 1;
});
const unsubscribe1 = store.subscribe(() => {});
const unsubscribe1 = store.subscribe(() => { });
assert.equal(called, 1);
const unsubscribe2 = store.subscribe(() => {});
const unsubscribe2 = store.subscribe(() => { });
assert.equal(called, 1);
unsubscribe1();
@ -73,7 +73,7 @@ describe('store', () => {
set(0);
return () => {
tick = () => {};
tick = () => { };
running = false;
};
});
@ -242,11 +242,23 @@ describe('store', () => {
assert.deepEqual(cleaned_up, [2, 3, 4]);
});
it('allows derived with different types', () => {
const a = writable('one');
const b = writable(1);
const c = derived([a, b], ([a, b]) => `${a} ${b}`);
assert.deepEqual(get(c), 'one 1');
a.set('two');
b.set(2);
assert.deepEqual(get(c), 'two 2');
});
});
describe('get', () => {
it('gets the current value of a store', () => {
const store = readable(42, () => {});
const store = readable(42, () => { });
assert.equal(get(store), 42);
});
});
Loading…
Cancel
Save