@nickchristensen/ppls 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1190 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +5 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/dist/add-command.d.ts +24 -0
- package/dist/add-command.js +47 -0
- package/dist/base-command.d.ts +63 -0
- package/dist/base-command.js +306 -0
- package/dist/commands/config/get.d.ts +11 -0
- package/dist/commands/config/get.js +34 -0
- package/dist/commands/config/init.d.ts +15 -0
- package/dist/commands/config/init.js +43 -0
- package/dist/commands/config/list.d.ts +13 -0
- package/dist/commands/config/list.js +64 -0
- package/dist/commands/config/remove.d.ts +11 -0
- package/dist/commands/config/remove.js +26 -0
- package/dist/commands/config/set.d.ts +12 -0
- package/dist/commands/config/set.js +58 -0
- package/dist/commands/correspondents/add.d.ts +12 -0
- package/dist/commands/correspondents/add.js +20 -0
- package/dist/commands/correspondents/delete.d.ts +16 -0
- package/dist/commands/correspondents/delete.js +18 -0
- package/dist/commands/correspondents/list.d.ts +9 -0
- package/dist/commands/correspondents/list.js +15 -0
- package/dist/commands/correspondents/show.d.ts +14 -0
- package/dist/commands/correspondents/show.js +17 -0
- package/dist/commands/correspondents/update.d.ts +18 -0
- package/dist/commands/correspondents/update.js +24 -0
- package/dist/commands/custom-fields/add.d.ts +16 -0
- package/dist/commands/custom-fields/add.js +91 -0
- package/dist/commands/custom-fields/delete.d.ts +16 -0
- package/dist/commands/custom-fields/delete.js +18 -0
- package/dist/commands/custom-fields/list.d.ts +9 -0
- package/dist/commands/custom-fields/list.js +12 -0
- package/dist/commands/custom-fields/show.d.ts +14 -0
- package/dist/commands/custom-fields/show.js +17 -0
- package/dist/commands/custom-fields/update.d.ts +20 -0
- package/dist/commands/custom-fields/update.js +93 -0
- package/dist/commands/document-types/add.d.ts +12 -0
- package/dist/commands/document-types/add.js +22 -0
- package/dist/commands/document-types/delete.d.ts +16 -0
- package/dist/commands/document-types/delete.js +18 -0
- package/dist/commands/document-types/list.d.ts +9 -0
- package/dist/commands/document-types/list.js +12 -0
- package/dist/commands/document-types/show.d.ts +14 -0
- package/dist/commands/document-types/show.js +17 -0
- package/dist/commands/document-types/update.d.ts +18 -0
- package/dist/commands/document-types/update.js +26 -0
- package/dist/commands/documents/add.d.ts +70 -0
- package/dist/commands/documents/add.js +166 -0
- package/dist/commands/documents/delete.d.ts +16 -0
- package/dist/commands/documents/delete.js +18 -0
- package/dist/commands/documents/download.d.ts +48 -0
- package/dist/commands/documents/download.js +152 -0
- package/dist/commands/documents/list.d.ts +9 -0
- package/dist/commands/documents/list.js +14 -0
- package/dist/commands/documents/show.d.ts +14 -0
- package/dist/commands/documents/show.js +19 -0
- package/dist/commands/documents/update.d.ts +25 -0
- package/dist/commands/documents/update.js +42 -0
- package/dist/commands/profile.d.ts +13 -0
- package/dist/commands/profile.js +19 -0
- package/dist/commands/tags/add.d.ts +17 -0
- package/dist/commands/tags/add.js +29 -0
- package/dist/commands/tags/delete.d.ts +16 -0
- package/dist/commands/tags/delete.js +18 -0
- package/dist/commands/tags/list.d.ts +10 -0
- package/dist/commands/tags/list.js +18 -0
- package/dist/commands/tags/show.d.ts +16 -0
- package/dist/commands/tags/show.js +24 -0
- package/dist/commands/tags/update.d.ts +21 -0
- package/dist/commands/tags/update.js +30 -0
- package/dist/delete-command.d.ts +20 -0
- package/dist/delete-command.js +48 -0
- package/dist/helpers/config-store.d.ts +4 -0
- package/dist/helpers/config-store.js +35 -0
- package/dist/helpers/date-utils.d.ts +3 -0
- package/dist/helpers/date-utils.js +27 -0
- package/dist/helpers/table.d.ts +20 -0
- package/dist/helpers/table.js +42 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/list-command.d.ts +49 -0
- package/dist/list-command.js +98 -0
- package/dist/paginated-command.d.ts +48 -0
- package/dist/paginated-command.js +89 -0
- package/dist/show-command.d.ts +27 -0
- package/dist/show-command.js +50 -0
- package/dist/types/correspondents.d.ts +28 -0
- package/dist/types/correspondents.js +1 -0
- package/dist/types/custom-fields.d.ts +18 -0
- package/dist/types/custom-fields.js +1 -0
- package/dist/types/document-types.d.ts +27 -0
- package/dist/types/document-types.js +1 -0
- package/dist/types/documents.d.ts +70 -0
- package/dist/types/documents.js +1 -0
- package/dist/types/profile.d.ts +15 -0
- package/dist/types/profile.js +1 -0
- package/dist/types/shared.d.ts +4 -0
- package/dist/types/shared.js +1 -0
- package/dist/types/tags.d.ts +31 -0
- package/dist/types/tags.js +1 -0
- package/dist/update-command.d.ts +28 -0
- package/dist/update-command.js +51 -0
- package/oclif.manifest.json +3313 -0
- package/package.json +87 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Document, DocumentUpdate } from '../../types/documents.js';
|
|
2
|
+
import { UpdateCommand } from '../../update-command.js';
|
|
3
|
+
export default class DocumentsUpdate extends UpdateCommand<DocumentUpdate, Document> {
|
|
4
|
+
static args: {
|
|
5
|
+
id: import("@oclif/core/interfaces").Arg<number, {
|
|
6
|
+
max?: number;
|
|
7
|
+
min?: number;
|
|
8
|
+
}>;
|
|
9
|
+
};
|
|
10
|
+
static description: string;
|
|
11
|
+
static examples: string[];
|
|
12
|
+
static flags: {
|
|
13
|
+
'archive-serial-number': import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
content: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
correspondent: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
created: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
'document-type': import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
'storage-path': import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
tag: import("@oclif/core/interfaces").OptionFlag<number[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
title: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
};
|
|
22
|
+
protected buildPayload(_args: unknown, flags: Record<string, unknown>): DocumentUpdate;
|
|
23
|
+
protected plainTemplate(document: Document): string | undefined;
|
|
24
|
+
protected updatePath(id: number | string): string;
|
|
25
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { UpdateCommand } from '../../update-command.js';
|
|
3
|
+
export default class DocumentsUpdate extends UpdateCommand {
|
|
4
|
+
static args = {
|
|
5
|
+
id: Args.integer({ description: 'Document id', required: true }),
|
|
6
|
+
};
|
|
7
|
+
static description = 'Update a document';
|
|
8
|
+
static examples = ['<%= config.bin %> <%= command.id %> 123 --title "Receipt"'];
|
|
9
|
+
static flags = {
|
|
10
|
+
'archive-serial-number': Flags.integer({ description: 'Archive serial number' }),
|
|
11
|
+
content: Flags.string({ description: 'Document content' }),
|
|
12
|
+
correspondent: Flags.integer({ description: 'Correspondent id' }),
|
|
13
|
+
created: Flags.string({ description: 'Document created date' }),
|
|
14
|
+
'document-type': Flags.integer({ description: 'Document type id' }),
|
|
15
|
+
'storage-path': Flags.integer({ description: 'Storage path id' }),
|
|
16
|
+
tag: Flags.integer({ description: 'Tag id (repeatable)', multiple: true }),
|
|
17
|
+
title: Flags.string({ description: 'Document title' }),
|
|
18
|
+
};
|
|
19
|
+
buildPayload(_args, flags) {
|
|
20
|
+
const typedFlags = flags;
|
|
21
|
+
return {
|
|
22
|
+
'archive_serial_number': typedFlags['archive-serial-number'],
|
|
23
|
+
content: typedFlags.content,
|
|
24
|
+
correspondent: typedFlags.correspondent,
|
|
25
|
+
created: typedFlags.created,
|
|
26
|
+
'document_type': typedFlags['document-type'],
|
|
27
|
+
'storage_path': typedFlags['storage-path'],
|
|
28
|
+
tags: typedFlags.tag,
|
|
29
|
+
title: typedFlags.title,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
plainTemplate(document) {
|
|
33
|
+
const title = document.title?.trim();
|
|
34
|
+
if (!title) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
return `[${document.id}] ${title}`;
|
|
38
|
+
}
|
|
39
|
+
updatePath(id) {
|
|
40
|
+
return `/api/documents/${id}/`;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Profile } from '../types/profile.js';
|
|
2
|
+
import { ShowCommand } from '../show-command.js';
|
|
3
|
+
export default class ProfileCommand extends ShowCommand<Profile> {
|
|
4
|
+
static aliases: string[];
|
|
5
|
+
static description: string;
|
|
6
|
+
static examples: string[];
|
|
7
|
+
protected plainTemplate(profile: Profile): string | undefined;
|
|
8
|
+
protected showId(_args: {
|
|
9
|
+
id: number | string;
|
|
10
|
+
}): number | string;
|
|
11
|
+
protected showPath(_id: number | string): string;
|
|
12
|
+
protected transformResult(profile: Profile): Profile;
|
|
13
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ShowCommand } from '../show-command.js';
|
|
2
|
+
export default class ProfileCommand extends ShowCommand {
|
|
3
|
+
static aliases = ['whoami'];
|
|
4
|
+
static description = 'Show profile details';
|
|
5
|
+
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
6
|
+
plainTemplate(profile) {
|
|
7
|
+
return `${profile.first_name} ${profile.last_name} <${profile.email}>`;
|
|
8
|
+
}
|
|
9
|
+
showId(_args) {
|
|
10
|
+
return '';
|
|
11
|
+
}
|
|
12
|
+
showPath(_id) {
|
|
13
|
+
return '/api/profile/';
|
|
14
|
+
}
|
|
15
|
+
transformResult(profile) {
|
|
16
|
+
delete profile.password;
|
|
17
|
+
return profile;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Tag, TagCreate } from '../../types/tags.js';
|
|
2
|
+
import { AddCommand } from '../../add-command.js';
|
|
3
|
+
export default class TagsAdd extends AddCommand<TagCreate, Tag> {
|
|
4
|
+
static args: {
|
|
5
|
+
name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static description: string;
|
|
8
|
+
static examples: string[];
|
|
9
|
+
static flags: {
|
|
10
|
+
color: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
inbox: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
parent: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
};
|
|
14
|
+
protected createPath: string;
|
|
15
|
+
protected buildPayload(args: unknown, flags: Record<string, unknown>): TagCreate;
|
|
16
|
+
protected plainTemplate(tag: Tag): string | undefined;
|
|
17
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { AddCommand } from '../../add-command.js';
|
|
3
|
+
export default class TagsAdd extends AddCommand {
|
|
4
|
+
static args = {
|
|
5
|
+
name: Args.string({ description: 'Tag name', required: true }),
|
|
6
|
+
};
|
|
7
|
+
static description = 'Create a tag';
|
|
8
|
+
static examples = ['<%= config.bin %> <%= command.id %> Inbox'];
|
|
9
|
+
static flags = {
|
|
10
|
+
color: Flags.string({ description: 'Tag color (hex value)' }),
|
|
11
|
+
inbox: Flags.boolean({ description: 'Mark tag as an inbox tag' }),
|
|
12
|
+
parent: Flags.integer({ description: 'Parent tag id' }),
|
|
13
|
+
};
|
|
14
|
+
createPath = '/api/tags/';
|
|
15
|
+
buildPayload(args, flags) {
|
|
16
|
+
const typedArgs = args;
|
|
17
|
+
const typedFlags = flags;
|
|
18
|
+
return {
|
|
19
|
+
color: typedFlags.color,
|
|
20
|
+
'is_inbox_tag': typedFlags.inbox ? true : undefined,
|
|
21
|
+
'matching_algorithm': 6,
|
|
22
|
+
name: typedArgs.name,
|
|
23
|
+
parent: typedFlags.parent,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
plainTemplate(tag) {
|
|
27
|
+
return `[${tag.id}] ${tag.name}`;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DeleteCommand } from '../../delete-command.js';
|
|
2
|
+
export default class TagsDelete extends DeleteCommand {
|
|
3
|
+
static args: {
|
|
4
|
+
id: import("@oclif/core/interfaces").Arg<number, {
|
|
5
|
+
max?: number;
|
|
6
|
+
min?: number;
|
|
7
|
+
}>;
|
|
8
|
+
};
|
|
9
|
+
static description: string;
|
|
10
|
+
static examples: string[];
|
|
11
|
+
static flags: {
|
|
12
|
+
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
};
|
|
14
|
+
protected deleteLabel(id: number | string): string;
|
|
15
|
+
protected deletePath(id: number | string): string;
|
|
16
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { DeleteCommand } from '../../delete-command.js';
|
|
3
|
+
export default class TagsDelete extends DeleteCommand {
|
|
4
|
+
static args = {
|
|
5
|
+
id: Args.integer({ description: 'Tag id', required: true }),
|
|
6
|
+
};
|
|
7
|
+
static description = 'Delete a tag';
|
|
8
|
+
static examples = ['<%= config.bin %> <%= command.id %> 123'];
|
|
9
|
+
static flags = {
|
|
10
|
+
yes: Flags.boolean({ char: 'y', description: 'Skip confirmation prompt' }),
|
|
11
|
+
};
|
|
12
|
+
deleteLabel(id) {
|
|
13
|
+
return `tag ${id}`;
|
|
14
|
+
}
|
|
15
|
+
deletePath(id) {
|
|
16
|
+
return `/api/tags/${id}/`;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Tag, TagApi } from '../../types/tags.js';
|
|
2
|
+
import { ListCommand } from '../../list-command.js';
|
|
3
|
+
export default class TagsList extends ListCommand<TagApi, Tag> {
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
protected listPath: string;
|
|
7
|
+
protected tableAttrs: string[];
|
|
8
|
+
protected plainTemplate(tag: Tag): string | undefined;
|
|
9
|
+
protected transformResult(tag: TagApi): Tag;
|
|
10
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ListCommand } from '../../list-command.js';
|
|
2
|
+
export default class TagsList extends ListCommand {
|
|
3
|
+
static description = 'List tags';
|
|
4
|
+
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
5
|
+
listPath = '/api/tags/';
|
|
6
|
+
tableAttrs = ['id', 'name', 'slug', 'document_count'];
|
|
7
|
+
plainTemplate(tag) {
|
|
8
|
+
const count = tag.document_count;
|
|
9
|
+
const suffix = count === undefined ? '' : ` (${count} ${count === 1 ? 'document' : 'documents'})`;
|
|
10
|
+
return `[${tag.id}] ${tag.name}${suffix}`;
|
|
11
|
+
}
|
|
12
|
+
transformResult(tag) {
|
|
13
|
+
return {
|
|
14
|
+
...tag,
|
|
15
|
+
children: tag.children.map((child) => child.id),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Tag, TagApi } from '../../types/tags.js';
|
|
2
|
+
import { ShowCommand } from '../../show-command.js';
|
|
3
|
+
export declare const isHexColor: (value: string) => boolean;
|
|
4
|
+
export default class TagsShow extends ShowCommand<TagApi, Tag> {
|
|
5
|
+
static args: {
|
|
6
|
+
id: import("@oclif/core/interfaces").Arg<number, {
|
|
7
|
+
max?: number;
|
|
8
|
+
min?: number;
|
|
9
|
+
}>;
|
|
10
|
+
};
|
|
11
|
+
static description: string;
|
|
12
|
+
static examples: string[];
|
|
13
|
+
protected plainTemplate(tag: Tag): string | undefined;
|
|
14
|
+
protected showPath(id: number | string): string;
|
|
15
|
+
protected transformResult(tag: TagApi): Tag;
|
|
16
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Args } from '@oclif/core';
|
|
2
|
+
import { ShowCommand } from '../../show-command.js';
|
|
3
|
+
export const isHexColor = (value) => /^#([0-9A-Fa-f]{3}){1,2}$/.test(value);
|
|
4
|
+
export default class TagsShow extends ShowCommand {
|
|
5
|
+
static args = {
|
|
6
|
+
id: Args.integer({ description: 'Tag id', required: true }),
|
|
7
|
+
};
|
|
8
|
+
static description = 'Show tag details';
|
|
9
|
+
static examples = ['<%= config.bin %> <%= command.id %> 123'];
|
|
10
|
+
plainTemplate(tag) {
|
|
11
|
+
const count = tag.document_count;
|
|
12
|
+
const suffix = count === undefined ? '' : ` (${count} ${count === 1 ? 'document' : 'documents'})`;
|
|
13
|
+
return `[${tag.id}] ${tag.name}${suffix}`;
|
|
14
|
+
}
|
|
15
|
+
showPath(id) {
|
|
16
|
+
return `/api/tags/${id}/`;
|
|
17
|
+
}
|
|
18
|
+
transformResult(tag) {
|
|
19
|
+
return {
|
|
20
|
+
...tag,
|
|
21
|
+
children: tag.children.map((child) => child.id),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Tag, TagUpdate } from '../../types/tags.js';
|
|
2
|
+
import { UpdateCommand } from '../../update-command.js';
|
|
3
|
+
export default class TagsUpdate extends UpdateCommand<TagUpdate, Tag> {
|
|
4
|
+
static args: {
|
|
5
|
+
id: import("@oclif/core/interfaces").Arg<number, {
|
|
6
|
+
max?: number;
|
|
7
|
+
min?: number;
|
|
8
|
+
}>;
|
|
9
|
+
};
|
|
10
|
+
static description: string;
|
|
11
|
+
static examples: string[];
|
|
12
|
+
static flags: {
|
|
13
|
+
color: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
inbox: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
parent: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
};
|
|
18
|
+
protected buildPayload(_args: unknown, flags: Record<string, unknown>): TagUpdate;
|
|
19
|
+
protected plainTemplate(tag: Tag): string | undefined;
|
|
20
|
+
protected updatePath(id: number | string): string;
|
|
21
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { UpdateCommand } from '../../update-command.js';
|
|
3
|
+
export default class TagsUpdate extends UpdateCommand {
|
|
4
|
+
static args = {
|
|
5
|
+
id: Args.integer({ description: 'Tag id', required: true }),
|
|
6
|
+
};
|
|
7
|
+
static description = 'Update a tag';
|
|
8
|
+
static examples = ['<%= config.bin %> <%= command.id %> 123 --name Inbox'];
|
|
9
|
+
static flags = {
|
|
10
|
+
color: Flags.string({ description: 'Tag color (hex value)' }),
|
|
11
|
+
inbox: Flags.boolean({ allowNo: true, description: 'Mark tag as an inbox tag' }),
|
|
12
|
+
name: Flags.string({ description: 'Tag name' }),
|
|
13
|
+
parent: Flags.integer({ description: 'Parent tag id' }),
|
|
14
|
+
};
|
|
15
|
+
buildPayload(_args, flags) {
|
|
16
|
+
const typedFlags = flags;
|
|
17
|
+
return {
|
|
18
|
+
color: typedFlags.color,
|
|
19
|
+
'is_inbox_tag': typedFlags.inbox,
|
|
20
|
+
name: typedFlags.name,
|
|
21
|
+
parent: typedFlags.parent,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
plainTemplate(tag) {
|
|
25
|
+
return `[${tag.id}] ${tag.name}`;
|
|
26
|
+
}
|
|
27
|
+
updatePath(id) {
|
|
28
|
+
return `/api/tags/${id}/`;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { BaseCommand } from './base-command.js';
|
|
2
|
+
type DeleteCommandArgs = {
|
|
3
|
+
id: number | string;
|
|
4
|
+
};
|
|
5
|
+
type DeleteCommandFlags = {
|
|
6
|
+
yes?: boolean;
|
|
7
|
+
};
|
|
8
|
+
type DeleteCommandResult<TResponse> = null | TResponse | {
|
|
9
|
+
deleted: true;
|
|
10
|
+
id: number | string;
|
|
11
|
+
};
|
|
12
|
+
export declare abstract class DeleteCommand<TResponse = unknown> extends BaseCommand {
|
|
13
|
+
protected deleteId(args: DeleteCommandArgs): number | string;
|
|
14
|
+
protected abstract deleteLabel(id: number | string): string;
|
|
15
|
+
protected deleteMessage(id: number | string, _result: null | TResponse): string | undefined;
|
|
16
|
+
protected abstract deletePath(id: number | string): string;
|
|
17
|
+
protected ensureConfirmed(flags: DeleteCommandFlags, id: number | string): Promise<void>;
|
|
18
|
+
run(): Promise<DeleteCommandResult<TResponse>>;
|
|
19
|
+
}
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createInterface } from 'node:readline';
|
|
2
|
+
import { BaseCommand } from './base-command.js';
|
|
3
|
+
export class DeleteCommand extends BaseCommand {
|
|
4
|
+
deleteId(args) {
|
|
5
|
+
return args.id;
|
|
6
|
+
}
|
|
7
|
+
deleteMessage(id, _result) {
|
|
8
|
+
return `Deleted ${this.deleteLabel(id)}`;
|
|
9
|
+
}
|
|
10
|
+
async ensureConfirmed(flags, id) {
|
|
11
|
+
if (flags.yes) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (!process.stdin.isTTY) {
|
|
15
|
+
this.error('Confirmation required. Re-run with --yes to proceed.');
|
|
16
|
+
}
|
|
17
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
18
|
+
const answer = await new Promise((resolve) => {
|
|
19
|
+
rl.question(`Delete ${this.deleteLabel(id)}? (y/N) `, (response) => resolve(response));
|
|
20
|
+
});
|
|
21
|
+
rl.close();
|
|
22
|
+
const confirmed = ['y', 'yes'].includes(answer.trim().toLowerCase());
|
|
23
|
+
if (!confirmed) {
|
|
24
|
+
this.exit(0);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async run() {
|
|
28
|
+
const { args, flags, metadata } = await this.parse();
|
|
29
|
+
const resolvedFlags = await this.resolveGlobalFlags(flags, metadata);
|
|
30
|
+
const apiFlags = {
|
|
31
|
+
headers: resolvedFlags.headers,
|
|
32
|
+
hostname: resolvedFlags.hostname,
|
|
33
|
+
token: resolvedFlags.token,
|
|
34
|
+
};
|
|
35
|
+
const deleteFlags = flags;
|
|
36
|
+
const id = this.deleteId(args);
|
|
37
|
+
await this.ensureConfirmed(deleteFlags, id);
|
|
38
|
+
const result = await this.deleteApiJson(apiFlags, this.deletePath(id));
|
|
39
|
+
if (this.jsonEnabled()) {
|
|
40
|
+
return result === null ? { deleted: true, id } : result;
|
|
41
|
+
}
|
|
42
|
+
const message = this.deleteMessage(id, result);
|
|
43
|
+
if (message) {
|
|
44
|
+
this.log(message);
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type ConfigData = Record<string, unknown>;
|
|
2
|
+
export declare const configPath: (configDir: string) => string;
|
|
3
|
+
export declare const readConfig: (configDir: string) => Promise<ConfigData>;
|
|
4
|
+
export declare const writeConfig: (configDir: string, config: ConfigData) => Promise<void>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export const configPath = (configDir) => path.join(configDir, 'config.json');
|
|
4
|
+
export const readConfig = async (configDir) => {
|
|
5
|
+
const configFile = configPath(configDir);
|
|
6
|
+
let rawConfig;
|
|
7
|
+
try {
|
|
8
|
+
rawConfig = await readFile(configFile, 'utf8');
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
const typedError = error;
|
|
12
|
+
if (typedError.code === 'ENOENT') {
|
|
13
|
+
return {};
|
|
14
|
+
}
|
|
15
|
+
const message = typedError.message ?? String(error);
|
|
16
|
+
throw new Error(`Failed to read config at ${configFile}: ${message}`);
|
|
17
|
+
}
|
|
18
|
+
let parsed;
|
|
19
|
+
try {
|
|
20
|
+
parsed = JSON.parse(rawConfig);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
24
|
+
throw new Error(`Failed to read config at ${configFile}: ${message}`);
|
|
25
|
+
}
|
|
26
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
27
|
+
throw new Error(`Config at ${configFile} must be a JSON object.`);
|
|
28
|
+
}
|
|
29
|
+
return parsed;
|
|
30
|
+
};
|
|
31
|
+
export const writeConfig = async (configDir, config) => {
|
|
32
|
+
const configFile = configPath(configDir);
|
|
33
|
+
await mkdir(configDir, { recursive: true });
|
|
34
|
+
await writeFile(configFile, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
|
|
35
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { format, formatRelative, isMatch, isValid, parse, parseISO } from 'date-fns';
|
|
2
|
+
const dateOnlyFormat = 'yyyy-MM-dd';
|
|
3
|
+
export const isDateOnly = (value) => isMatch(value, dateOnlyFormat);
|
|
4
|
+
export const isDateTime = (value) => {
|
|
5
|
+
if (!value.includes('T')) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
const parsedDate = parseISO(value);
|
|
9
|
+
if (!isValid(parsedDate)) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
return /(?:Z|[+-]\d{2}:\d{2})$/.test(value);
|
|
13
|
+
};
|
|
14
|
+
export const formatDateString = (value, dateFormat, baseDate = new Date()) => {
|
|
15
|
+
if (isDateOnly(value)) {
|
|
16
|
+
const parsedDate = parse(value, dateOnlyFormat, new Date());
|
|
17
|
+
if (dateFormat === 'relative') {
|
|
18
|
+
return formatRelative(parsedDate, baseDate).split(' at ')[0];
|
|
19
|
+
}
|
|
20
|
+
return format(parsedDate, dateFormat);
|
|
21
|
+
}
|
|
22
|
+
if (isDateTime(value)) {
|
|
23
|
+
const parsedDate = parseISO(value);
|
|
24
|
+
return dateFormat === 'relative' ? formatRelative(parsedDate, baseDate) : format(parsedDate, dateFormat);
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type * as TtyTable from 'tty-table';
|
|
2
|
+
export type TableColumn = TtyTable.Header;
|
|
3
|
+
export type TableFormatterContext = {
|
|
4
|
+
configure: (options: Record<string, unknown>) => void;
|
|
5
|
+
resetStyle: (cellValue: string) => string;
|
|
6
|
+
style: (cellValue: string, ...effects: string[]) => string;
|
|
7
|
+
};
|
|
8
|
+
export type TableFormatter = (this: TableFormatterContext, ...args: Parameters<TtyTable.Formatter>) => ReturnType<TtyTable.Formatter>;
|
|
9
|
+
export type TableOptions = TtyTable.Options & {
|
|
10
|
+
showHeader?: boolean;
|
|
11
|
+
};
|
|
12
|
+
export type TableRow = Record<string, unknown> | unknown[];
|
|
13
|
+
export declare const formatLabel: (value: string) => string;
|
|
14
|
+
export declare const formatField: TableFormatter;
|
|
15
|
+
export declare const createValueFormatter: (dateFormat: string) => TableFormatter;
|
|
16
|
+
type TtyTable = (headers: TableColumn[], rows: TableRow[], options?: TableOptions) => {
|
|
17
|
+
render(): string;
|
|
18
|
+
};
|
|
19
|
+
export declare const renderTable: (headers: TableColumn[], rows: TableRow[], options?: TableOptions) => string;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { formatDateString } from './date-utils.js';
|
|
3
|
+
export const formatLabel = (value) => value.replaceAll('_', ' ').replaceAll(/\b\w/g, (match) => match.toUpperCase());
|
|
4
|
+
export const formatField = function (cellValue) {
|
|
5
|
+
if (cellValue === null || cellValue === undefined) {
|
|
6
|
+
return '';
|
|
7
|
+
}
|
|
8
|
+
if (typeof cellValue === 'string') {
|
|
9
|
+
return formatLabel(cellValue);
|
|
10
|
+
}
|
|
11
|
+
return formatLabel(String(cellValue));
|
|
12
|
+
};
|
|
13
|
+
export const createValueFormatter = (dateFormat) => function (cellValue) {
|
|
14
|
+
if (cellValue === null || cellValue === undefined) {
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
if (typeof cellValue === 'string') {
|
|
18
|
+
const formattedDate = formatDateString(cellValue, dateFormat);
|
|
19
|
+
if (formattedDate) {
|
|
20
|
+
return this.style(String(formattedDate), 'magenta');
|
|
21
|
+
}
|
|
22
|
+
return cellValue;
|
|
23
|
+
}
|
|
24
|
+
if (typeof cellValue === 'number') {
|
|
25
|
+
return this.style(String(cellValue), 'blue');
|
|
26
|
+
}
|
|
27
|
+
if (typeof cellValue === 'boolean') {
|
|
28
|
+
return cellValue ? this.style(String('✔︎'), 'green', 'bold') : this.style(String('×'), 'red', 'bold');
|
|
29
|
+
}
|
|
30
|
+
return this.style(JSON.stringify(cellValue), 'yellow');
|
|
31
|
+
};
|
|
32
|
+
const require = createRequire(import.meta.url);
|
|
33
|
+
const ttyTable = require('tty-table');
|
|
34
|
+
export const renderTable = (headers, rows, options) => ttyTable(headers.map((header) => ({
|
|
35
|
+
alias: header.alias ?? formatLabel(header.value),
|
|
36
|
+
align: 'left',
|
|
37
|
+
headerAlign: 'left',
|
|
38
|
+
...header,
|
|
39
|
+
})), rows, {
|
|
40
|
+
compact: true,
|
|
41
|
+
...options,
|
|
42
|
+
}).render();
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { run } from '@oclif/core';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { run } from '@oclif/core';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { ApiFlags } from './base-command.js';
|
|
2
|
+
import { type TableColumn, type TableRow } from './helpers/table.js';
|
|
3
|
+
import { PaginatedCommand } from './paginated-command.js';
|
|
4
|
+
type ListCommandFlags = ApiFlags & {
|
|
5
|
+
'id-in'?: string;
|
|
6
|
+
'name-contains'?: string;
|
|
7
|
+
page?: number;
|
|
8
|
+
'page-size'?: number;
|
|
9
|
+
sort?: string;
|
|
10
|
+
};
|
|
11
|
+
type ListOutputFlags = ListCommandFlags & {
|
|
12
|
+
'date-format': string;
|
|
13
|
+
plain?: boolean;
|
|
14
|
+
table?: boolean;
|
|
15
|
+
};
|
|
16
|
+
type TableColumnInput = string | TableColumn;
|
|
17
|
+
export declare abstract class ListCommand<TRaw extends TableRow = TableRow, TOutput extends TableRow = TRaw> extends PaginatedCommand {
|
|
18
|
+
static baseFlags: {
|
|
19
|
+
'id-in': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
'name-contains': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
sort: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
22
|
+
page: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
23
|
+
'page-size': import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
24
|
+
'date-format': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
25
|
+
header: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
26
|
+
hostname: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
27
|
+
plain: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
28
|
+
table: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
29
|
+
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
30
|
+
};
|
|
31
|
+
protected abstract listPath: string;
|
|
32
|
+
protected abstract tableAttrs: TableColumnInput[];
|
|
33
|
+
protected fetchListResults<T>(options: {
|
|
34
|
+
flags: ListCommandFlags;
|
|
35
|
+
params?: Record<string, number | string | undefined>;
|
|
36
|
+
path: string;
|
|
37
|
+
}): Promise<T[]>;
|
|
38
|
+
protected listParams(flags: ListCommandFlags): Record<string, number | string | undefined>;
|
|
39
|
+
protected abstract plainTemplate(item: TOutput): null | string | undefined;
|
|
40
|
+
protected renderListOutput(options: {
|
|
41
|
+
flags: ListOutputFlags;
|
|
42
|
+
results: TOutput[];
|
|
43
|
+
}): void;
|
|
44
|
+
run(): Promise<TOutput[]>;
|
|
45
|
+
protected shouldAutoPaginate(flags: ListCommandFlags): boolean;
|
|
46
|
+
protected transformResult(result: TRaw): TOutput;
|
|
47
|
+
protected transformResults(results: TRaw[]): TOutput[];
|
|
48
|
+
}
|
|
49
|
+
export {};
|