Skip to content

Commit 6e0a8cf

Browse files
authored
Refactor v2 (#1)
* refactor: reduce unnecessary logics * refactor(parser): refactor splitStatemtents * refactor: refactor serialization flow * chore(vscode): use transpileOnly * 2.0.0-alpha.0 * fix: load all files on create program * 2.0.0-alpha.1 * refactor: tidy up * refactor(v2): separate main API into type injection and printer * refactor(v2): update interfaces * chore: readme * 2.0.0
1 parent ea51f8f commit 6e0a8cf

25 files changed

+937
-1059
lines changed

.vscode/launch.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,11 @@
1111
"node",
1212
"-r",
1313
// this is necessary if we want to use inspect command with ts-node
14-
"ts-node/register",
14+
"ts-node/register/transpile-only",
1515
// this makes the process hold until a debugger connected 9229
1616
"--inspect-brk=9229",
1717
"${workspaceFolder}/sample/init.ts"
1818
],
19-
"env": {
20-
"TS_NODE_FILES": "true",
21-
},
2219
// the debugger will try to to connect any debug agent on port 9229
2320
"port": 9229,
2421
"skipFiles": [

README.md

Lines changed: 52 additions & 205 deletions
Original file line numberDiff line numberDiff line change
@@ -11,245 +11,92 @@ $ npm i -D typescript prettier ts-node # You can skip them if already installed.
1111

1212
## Usage
1313

14-
### Example
14+
### `typeshot.createType<Target, Props>([...parameters])`
1515

16-
#### `sample.typeshot.ts`
16+
This is the core API of `typeshot`. You can get TypeToken (token to print resolved type of `Target`).
1717

18-
Register types that you want to take snapshot.
18+
When `Target` is a type reference and type arguments of the reference include the type `typeshot.T`, `typeshot.T` will be replaced with returned values type of given `parameters`. If there are multiple `typeshot.T`, they will be replaced from left to right. You can use `typeshot.T` in deeply nested type argument too.
1919

20-
```ts
21-
import typeshot from 'typeshot';
22-
23-
typeshot.configuration({ output: './sample.generated.ts' })`
24-
// DO NOT EDIT - GENERATED FILE
25-
`;
26-
// typeshot-output-header
27-
28-
// eslint-disable-next-line no-console
29-
console.log('Loaded Generated File!');
30-
31-
// typeshot-header
32-
import type { Type, GenericType } from './another-file';
33-
type EntryMap<T extends object> = {
34-
[K in keyof T]: readonly [K, T[K]];
35-
};
36-
37-
// typeshot-main
38-
typeshot.takeStatic<typeshot.Expand<Type>>('UniqueKey-0', 'TypeName')`
39-
// Descriptions of '${typeshot.TemplateSymbols.NAME}'
40-
export ${typeshot.TemplateSymbols.DECLARATION}
41-
export type ${typeshot.TemplateSymbols.NAME}Array = ${typeshot.TemplateSymbols.NAME}[];
42-
export const ${typeshot.TemplateSymbols.NAME}__sample: ${typeshot.TemplateSymbols.NAME} = { /* ... */ } as any;
43-
`;
44-
45-
typeshot.takeStatic<EntryMap<Type>>('UniqueKey-1', 'TypeNameForEntryMap')`
46-
export ${typeshot.TemplateSymbols.DECLARATION}
47-
`;
48-
49-
interface DynamicTypeshotProps {
50-
param: string;
51-
}
52-
53-
const stringParam = typeshot.createPrameter<DynamicTypeshotProps, string>(({ param }) => [param]);
54-
55-
const takeDynamic = typeshot
56-
.createDynamic<GenericType<typeshot.T>>('UniqueKey-2')
57-
.parameters<DynamicTypeshotProps>([stringParam])
58-
.names(({ param }) => `GenericType__${param.toUpperCase()}`)`
59-
// ${({ param }) => param}
60-
export ${typeshot.TemplateSymbols.DECLARATION}
61-
`;
62-
63-
takeDynamic({ param: 'foo' });
64-
takeDynamic({ param: 'bar' });
65-
```
66-
67-
#### `another-file.ts`
68-
69-
This is dependency file that is loaded from `sample.typeshot.ts`.
20+
`parameters` is array of function that recieves props and returns a value of parameter you inject to `Target`. The value will be internally converted into appropriate AST(Abstract Syntax Tree) node so that you don't have to use TypeScript Compiler API. See `typeshot.createParameter` section about how to set up `parameters`.
7021

22+
There are three kind of TypeToken (alias, interface and literal) and several approaches to get tokens.
7123
```ts
72-
export interface Type {
73-
foo: string;
74-
bar: {
75-
baz: number;
76-
qux: Date;
77-
};
78-
}
79-
80-
export type GenericType<T extends string> = {
81-
[K in T]: { type: K };
82-
};
83-
```
24+
const type = typeshot.createType<Target, Props>([...parameters]);
8425

85-
#### run-typeshot.ts
86-
There is no CLI for `typeshot` yet.
87-
```ts
88-
import runTypeshot from 'typeshot/program';
89-
90-
runTypeshot({ test: /\.typeshot\.ts$/ });
91-
```
26+
typeshot.print`
27+
// Target as type alias format, the name is 'TypeAsAlias'
28+
export ${type(props).alias('TypeAsAlias')}
9229
93-
Execute via `ts-node`
30+
// Target as interface format, the name is 'TypeAsInterface'
31+
export ${type(props).interface('TypeAsInterface')}
9432
95-
```sh
96-
$ ts-node --files run-typeshot.ts
97-
```
33+
// Target as type literal format, you cannot name it since it's type literal
34+
export type TypeAsLiteral = ${type(props).literal()};
35+
`;
9836

99-
#### `sample.generated.ts`
37+
const [First, Second, Third] = type(props).mapArray(['First', 'Second', 'Third']);
38+
typeshot.print`
39+
// Target[0] as type alias format, the name is 'First'
40+
export ${First.alias}
10041
101-
This is the output file of `typeshot` with `sample.typeshot.ts`.
42+
// Target[1] as interface format, the name is 'Second'
43+
export ${Second.interface}
10244
103-
```ts
104-
// DO NOT EDIT - GENERATED FILE
105-
// typeshot-output-header
106-
// eslint-disable-next-line no-console
107-
console.log('Loaded Generated File!');
108-
// Descriptions of 'TypeName'
109-
export type TypeName = {
110-
foo: string;
111-
bar: {
112-
baz: number;
113-
qux: Date;
114-
};
115-
};
116-
export type TypeNameArray = TypeName[];
117-
export const TypeName__sample: TypeName = {
118-
/* ... */
119-
} as any;
120-
121-
export type TypeNameForEntryMap = {
122-
foo: readonly ['foo', string];
123-
bar: readonly [
124-
'bar',
125-
{
126-
baz: number;
127-
qux: Date;
128-
},
129-
];
130-
};
131-
132-
// foo
133-
export type GenericType__FOO = {
134-
foo: {
135-
type: 'foo';
136-
};
137-
};
138-
139-
// bar
140-
export type GenericType__BAR = {
141-
bar: {
142-
type: 'bar';
143-
};
144-
};
145-
146-
export {};
147-
```
148-
149-
### API
45+
// Target[2] as type literal format, the named is 'Third' but ignored since the format is literal
46+
export type Third = ${Third.literal};
47+
`;
48+
console.log(First.property, First.name); // 0, 'First'
49+
console.log(Second.property, Second.name); // 1, 'Second'
50+
console.log(Third.property, Third.name); // 2, 'Third'
15051

151-
#### `typeshot.takeStatic`
52+
const { foo, bar, baz } = type(props).mapRecord({ foo: 'Foo', bar: 'Bar', baz: 'Baz' });
53+
typeshot.print`
54+
// Target['foo'] as type alias format, the name is 'Foo'
55+
export ${foo.alias}
15256
153-
This is the most basic usage of `typeshot`. You can take a snapshot of type.
57+
// Target['bar'] as interface format, the name is 'Bar'
58+
export ${bar.interface}
15459
155-
```ts
156-
typeshot.takeStatic<SnapshotEntryType>('Unique Key', 'TypeName')`
157-
// output code as string
158-
${typeshot.TemplateSymbols.NAME}
159-
${typeshot.TemplateSymbols.CONTENT}
160-
${typeshot.TemplateSymbols.DECLARATION}
60+
// Target['baz'] as type literal format, the named is 'Baz' but ignored since the format is literal
61+
export type Baz = ${baz.literal};
16162
`;
63+
console.log(foo.property, foo.name); // 0, 'Foo'
64+
console.log(bar.property, bar.name); // 1, 'Bar'
65+
console.log(baz.property, baz.name); // 2, 'Baz'
16266
```
163-
The type parameter at where `SnapshotEntryType` is placed, is the entry. `typeshot` serialize actual type structure of the entry.
16467

165-
The first argument is a key as pure string literal, don't use template string. Each key should be unique in the file.
68+
Please use it as `typeshot.createType` not `createType` in order to parse and inject needed values.
16669

167-
The second argument is name of generated type.
70+
### `typeshot.createParameter<Parameter, Props>((props: P) => { ... })`
16871

169-
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.
72+
This helps to set up parameter function for the sake of `typeshot.createType`. The value of parameter have to be wrapped by `typeshot.solo`, `typeshot.union`, or `typeshot.intersection`. As their name, you can create Union Type and Intersection Type with `union` and `intersection`. `solo` is for single type.
17073

171-
#### `typeshot.createDynamic`
172-
```ts
173-
interface DynamicTypeshotProps {
174-
param: string;
175-
}
176-
const stringParam = typeshot.createPrameter<DynamicTypeshotProps, string>(({ param }) => [param]);
177-
const takeDynamic = typeshot
178-
.createDynamic<GenericType<typeshot.T>>('UniqueKey')
179-
.parameters<DynamicTypeshotProps>([stringParam])
180-
.names(({ param }) => param.toUpperCase())`
181-
// ${({ param }) => param}
182-
export ${typeshot.TemplateSymbols.DECLARATION}
183-
`;
74+
### `typeshot.print`
18475

185-
takeDynamic({ param: 'foo' });
186-
takeDynamic({ param: 'bar' });
187-
```
76+
This accumulates output contents immediately. You can use Type Token but a function.
18877

189-
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.
78+
### `typeshot.createPrinter<Props>`
79+
This returns a printer function to accumulate output contents. You can use a function in template substitutions.
19080

191-
The `parameters` phase is for specifying replacement of `typeshot.T`.<br>
192-
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.<br>
193-
I recommend you to prepare type injection with `typeshot.createParameter`. It helps you to create injection with value typed correctly.
81+
### `typeshot.createTemplate<Props>`
82+
WIP
19483

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.
84+
### `// typeshot-start` and `// typeshot-end` Comments
19885

199-
As the example, you can use function in the tagged template.
86+
Lines before `// typeshot-start` and lines after `// typeshot-end` are kept in output file. Both are optional so that you can skip it.
20087

201-
You can set the type of argument of each function in the type parameter of `parameters` phase.
88+
Some types or values should still necessary in the output file. You can write such code by using these comments.
20289

203-
#### `typeshot.configuration`
90+
### `typeshot.config`
20491

20592
You can specify path of output file and header content of output file.
20693

20794
```ts
208-
typeshot.configuration({ output: './sample.generated.ts' })`
95+
typeshot.config({ output: './sample.generated.ts' })`
20996
// DO NOT EDIT - GENERATED FILE
21097
`;
21198
```
21299

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`) |
253100

254101

255102
### Execution
@@ -265,7 +112,7 @@ runTypeshot({ test: /\.typeshot\.ts$/ });
265112
```
266113

267114
```sh
268-
$ ts-node --files run-typeshot.ts
115+
$ ts-node-transpile-only run-typeshot.ts
269116
```
270117

271118
#### Options

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "typeshot",
3-
"version": "1.3.4",
3+
"version": "2.0.0",
44
"description": "typeshot is a code generator like snapshot library, for TypeScript Declaration Files",
55
"main": "index.js",
66
"scripts": {

sample/readme/generated/sample.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// DO NOT EDIT - GENERATED FILE
2+
3+
// eslint-disable-next-line no-console
4+
console.log('Start Loading Generated File!');
5+
6+
// typeshot-start
7+
// You can write comments here.
8+
export type SampleType = {
9+
foo: string;
10+
bar: {
11+
baz: number;
12+
qux: Date;
13+
};
14+
};
15+
export type SampleTypeArray = SampleType[];
16+
export const SampleType__sample = { foo: 'foo', bar: { baz: 0, qux: new Date() } } as any;
17+
18+
export type FooAlias = {
19+
foo: {
20+
type: 'foo';
21+
};
22+
};
23+
export interface FooInterface {
24+
foo: {
25+
type: 'foo';
26+
};
27+
}
28+
export type Foo = {
29+
fooo: {
30+
foo: {
31+
type: 'foo';
32+
};
33+
};
34+
};
35+
36+
export type BarAlias = {
37+
bar: {
38+
type: 'bar';
39+
};
40+
};
41+
export interface BarInterface {
42+
bar: {
43+
type: 'bar';
44+
};
45+
}
46+
export type Bar = {
47+
fooo: {
48+
bar: {
49+
type: 'bar';
50+
};
51+
};
52+
};
53+
54+
// typeshot-end
55+
// eslint-disable-next-line no-console
56+
console.log('Finish Loading Generated File!');
57+
58+
export {};

0 commit comments

Comments
 (0)