Skip to content

Commit 2ea9efd

Browse files
committed
feat(readme): write readme
1 parent 45299a5 commit 2ea9efd

File tree

3 files changed

+281
-1
lines changed

3 files changed

+281
-1
lines changed

README.md

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,285 @@
11
# typeshot
22

3+
`typeshot` is a code generator like snapshot library, for TypeScript Declaration Files.
4+
5+
## Motivation
6+
7+
8+
TypeScript developers have
9+
310
## Installation
411

12+
```sh
13+
$ npm i -D typeshot
14+
$ npm i -D typescript prettier ts-node # You can skip them if already installed.
15+
```
16+
517
## Usage
618

19+
### Example
20+
21+
#### `sample.typeshot.ts`
22+
23+
Register types that you want to take snapshot.
24+
25+
```ts
26+
import typeshot from 'typeshot';
27+
28+
typeshot.configuration({ output: './sample.generated.ts' })`
29+
// DO NOT EDIT - GENERATED FILE
30+
`;
31+
// typeshot-output-header
32+
33+
// eslint-disable-next-line no-console
34+
console.log('Loaded Generated File!');
35+
36+
// typeshot-header
37+
import type { Type, GenericType } from './another-file';
38+
type EntryMap<T extends object> = {
39+
[K in keyof T]: readonly [K, T[K]];
40+
};
41+
42+
// typeshot-main
43+
typeshot.takeStatic<typeshot.Expand<Type>>('UniqueKey-0', 'TypeName')`
44+
// Descriptions of '${typeshot.TemplateSymbols.NAME}'
45+
export ${typeshot.TemplateSymbols.DECLARATION}
46+
export type ${typeshot.TemplateSymbols.NAME}Array = ${typeshot.TemplateSymbols.NAME}[];
47+
export const ${typeshot.TemplateSymbols.NAME}__sample: ${typeshot.TemplateSymbols.NAME} = { /* ... */ } as any;
48+
`;
49+
50+
typeshot.takeStatic<EntryMap<Type>>('UniqueKey-1', 'TypeNameForEntryMap')`
51+
export ${typeshot.TemplateSymbols.DECLARATION}
52+
`;
53+
54+
interface DynamicTypeshotProps {
55+
param: string;
56+
}
57+
const takeDynamic = typeshot
58+
.createDynamic<GenericType<typeshot.T>>('UniqueKey-2')
59+
.parameters<DynamicTypeshotProps>(({ param }) => [param])
60+
.names(({ param }) => `GenericType__${param.toUpperCase()}`)`
61+
// ${({ param }) => param}
62+
export ${typeshot.TemplateSymbols.DECLARATION}
63+
`;
64+
65+
takeDynamic({ param: 'foo' });
66+
takeDynamic({ param: 'bar' });
67+
```
68+
69+
#### `another-file.ts`
70+
71+
This is dependency file that is loaded from `sample.typeshot.ts`.
72+
73+
```ts
74+
export interface Type {
75+
foo: string;
76+
bar: {
77+
baz: number;
78+
qux: Date;
79+
};
80+
}
81+
82+
export type GenericType<T extends string> = {
83+
[K in T]: { type: K };
84+
};
85+
```
86+
87+
#### run-typeshot.ts
88+
There is no CLI for `typeshot` yet.
89+
```ts
90+
import runTypeshot from 'typeshot/program';
91+
92+
runTypeshot({ test: /\.typeshot\.ts$/ });
93+
```
94+
95+
Execute via `ts-node`
96+
97+
```sh
98+
$ ts-node --files run-typeshot.ts
99+
```
100+
101+
#### `sample.generated.ts`
102+
103+
This is the output file of `typeshot` with `sample.typeshot.ts`.
104+
105+
```ts
106+
// DO NOT EDIT - GENERATED FILE
107+
// typeshot-output-header
108+
// eslint-disable-next-line no-console
109+
console.log('Loaded Generated File!');
110+
// Descriptions of 'TypeName'
111+
export type TypeName = {
112+
foo: string;
113+
bar: {
114+
baz: number;
115+
qux: Date;
116+
};
117+
};
118+
export type TypeNameArray = TypeName[];
119+
export const TypeName__sample: TypeName = {
120+
/* ... */
121+
} as any;
122+
123+
export type TypeNameForEntryMap = {
124+
foo: readonly ['foo', string];
125+
bar: readonly [
126+
'bar',
127+
{
128+
baz: number;
129+
qux: Date;
130+
},
131+
];
132+
};
133+
134+
// foo
135+
export type GenericType__FOO = {
136+
foo: {
137+
type: 'foo';
138+
};
139+
};
140+
141+
// bar
142+
export type GenericType__BAR = {
143+
bar: {
144+
type: 'bar';
145+
};
146+
};
147+
148+
export {};
149+
```
150+
151+
### API
152+
153+
#### `typeshot.takeStatic`
154+
155+
This is the most basic usage of `typeshot`. You can take a snapshot of type.
156+
157+
```ts
158+
typeshot.takeStatic<SnapshotEntryType>('Unique Key', 'TypeName')`
159+
// output code as string
160+
${typeshot.TemplateSymbols.NAME}
161+
${typeshot.TemplateSymbols.CONTENT}
162+
${typeshot.TemplateSymbols.DECLARATION}
163+
`;
164+
```
165+
The type parameter at where `SnapshotEntryType` is placed, is the entry. `typeshot` serialize actual type structure of the entry.
166+
167+
The first argument is a key as pure string literal, don't use template string. Each key should be unique in the file.
168+
169+
The second argument is name of generated type.
170+
171+
The tail of statement, tagged template string is written in output after symbols are replaced with generated type. It is described later section about symbols.
172+
173+
#### `typeshot.createDynamic`
174+
```ts
175+
interface DynamicTypeshotProps {
176+
param: string;
177+
}
178+
const takeDynamic = typeshot
179+
.createDynamic<GenericType<typeshot.T>>('UniqueKey')
180+
.parameters<DynamicTypeshotProps>(({ param }) => [param])
181+
.names(({ param }) => param.toUpperCase())`
182+
// ${({ param }) => param}
183+
export ${typeshot.TemplateSymbols.DECLARATION}
184+
`;
185+
186+
takeDynamic({ param: 'foo' });
187+
takeDynamic({ param: 'bar' });
188+
```
189+
190+
The difference from `typeshot.takeStatic` is that the second argument doesn't exist, two extra phases `parameters` and `names` are added, `typeshot.T` is available in entry type, and function is available in tagged template.
191+
192+
The `parameters` phase is for specifying replacement of `typeshot.T`.<br>
193+
You can use `typeshot.T` multiple times. The order that aliases are replaced is left to right, even if the entry type is deeply nested.
194+
195+
The `name` phase is for specifying name of generated type.<br>
196+
You can use two kinds of name descriptors. One is to use string as same as the second argument of `takeStatic`.<br>
197+
Another one is object(`Record<string, string>`) or array(`string[]`). When you use this way, the generated type is not entry type itself. `typeshot` use each type of property that is referred with keys of the object or array, and value of the key will be used as name.
198+
199+
As the example, you can use function in the tagged template.
200+
201+
You can set the type of argument of each function in the type parameter of `parameters` phase.
202+
203+
#### `typeshot.configuration`
204+
205+
You can specify path of output file and header content of output file.
206+
207+
```ts
208+
typeshot.configuration({ output: './sample.generated.ts' })`
209+
// DO NOT EDIT - GENERATED FILE
210+
`;
211+
```
212+
213+
#### Symbols
214+
| group | name | description |
215+
|:--------------- |:----------- |:----------- |
216+
|`TemplateSymbols`|`NAME` | name of output type |
217+
| |`CONTENT` | content of output type, generally object literal |
218+
| |`DECLARATION`| completed content of output type, as type alias |
219+
220+
#### Types
221+
| name | description |
222+
|:--------------- |:----------- |
223+
|`typeshot.T` | Type alias that will be replaced by dynamic parameter. See `typeshot.createDynamic` section about detail. |
224+
|`typeshot.Expand`| Generic type that helps to serialize types declared as `interface`.<br> For example, if `Type` in the example above was not wrapped with `typeshot.Expand`, it is serialized to `Type`, not object literal. |
225+
226+
### Section Comments
227+
228+
`typeshot` splits input file into several sections by spesific comments. Supports only single line comment.
229+
```ts
230+
console.log('unknown, will be ignored');
231+
232+
// section-comment-A
233+
console.log('section A start');
234+
/* statements */
235+
console.log('section A end');
236+
237+
// section-comment-B
238+
console.log('section B start');
239+
/* statements */
240+
console.log('section B end');
241+
```
242+
243+
Statements in each section are treated in different way.
244+
245+
| section name | kept or not in output | what kind of code should be written |
246+
|:---------------------- |:--------------------- |:----------------------------------- |
247+
|before sections | removed | used by also generated code (**transformed** `main`) |
248+
|`typeshot-output-header`| kept on the top | used by also generated code (**transformed** `main`) |
249+
|`typeshot-header` | removed | used by only **raw** `main` section |
250+
|`typeshot-main` | removed | `typeshot`'s code |
251+
|`typeshot-footer` | removed | used by only **raw** `main` section |
252+
|`typeshot-output-footer`| kept on the bottom | used by also generated code (**transformed** `main`) |
253+
254+
255+
### Execution
256+
257+
There is no CLI for `typeshot` yet.
258+
259+
Typeshot find entry files via tsconfig. So you have to include typeshot files by your tsconfig.<br>
260+
If you don't want to include them in your production tsconfig, you can create another tsconfig file for typeshot.
261+
```ts
262+
import runTypeshot from 'typeshot/program';
263+
264+
runTypeshot({ test: /\.typeshot\.ts$/ });
265+
```
266+
267+
```sh
268+
$ ts-node --files run-typeshot.ts
269+
```
270+
271+
#### Options
272+
273+
| name | type | description |
274+
|:--------------- |:------- | :---------- |
275+
|`test` | RegExp | **required**, pattern of typeshot file |
276+
|`project` | string | optional, path to `tsconfig.json` |
277+
|`prettierOptions`| object | optional, options of `prettier` |
278+
|`basePath` | string | optional, base path to find `tsconfig.json` and `.prettierrc` if they are ommited |
279+
280+
## TODO
281+
- implement CLI
282+
7283
## Committers
8284

9285
* Shota Hatada ([@whatasoda](https://github.com/whatasoda))

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "typeshot",
33
"version": "1.0.0",
4-
"description": "## Installation",
4+
"description": "typeshot is a code generator like snapshot library, for TypeScript Declaration Files",
55
"main": "index.js",
66
"scripts": {
77
"build": "rimraf ./lib && tsc -p tsconfig.lib.json && cp package.json README.md LICENSE ./lib",

tsconfig.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
"outDir": "lib",
2626
"declaration": true,
2727
"typeRoots": ["node_modules/@types"],
28+
"baseUrl": ".",
29+
"paths": {
30+
"typeshot": ["./src/typeshot.ts"]
31+
},
2832
},
2933
"exclude": ["node_modules"],
3034
"include": ["**/*"],

0 commit comments

Comments
 (0)