-
Notifications
You must be signed in to change notification settings - Fork 123
/
Copy pathSheetMapping.ts
132 lines (107 loc) · 3.84 KB
/
SheetMapping.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
* @license
* Copyright (c) 2025 Handsoncode. All rights reserved.
*/
import {NoSheetWithIdError, NoSheetWithNameError, SheetNameAlreadyTakenError} from '../errors'
import {TranslationPackage, UIElement} from '../i18n'
import {Maybe} from '../Maybe'
function canonicalize(sheetDisplayName: string): string {
return sheetDisplayName.toLowerCase()
}
class Sheet {
constructor(
public readonly id: number,
public displayName: string,
) {
}
public get canonicalName() {
return canonicalize(this.displayName)
}
}
export class SheetMapping {
private readonly mappingFromCanonicalName: Map<string, Sheet> = new Map()
private readonly mappingFromId: Map<number, Sheet> = new Map()
private readonly sheetNamePrefix: string
private lastSheetId = -1
constructor(private languages: TranslationPackage) {
this.sheetNamePrefix = languages.getUITranslation(UIElement.NEW_SHEET_PREFIX)
}
public addSheet(newSheetDisplayName: string = `${this.sheetNamePrefix}${this.lastSheetId + 2}`): number {
const newSheetCanonicalName = canonicalize(newSheetDisplayName)
if (this.mappingFromCanonicalName.has(newSheetCanonicalName)) {
throw new SheetNameAlreadyTakenError(newSheetDisplayName)
}
this.lastSheetId++
const sheet = new Sheet(this.lastSheetId, newSheetDisplayName)
this.store(sheet)
return sheet.id
}
public removeSheet(sheetId: number) {
const sheet = this.fetchSheetById(sheetId)
if (sheetId == this.lastSheetId) {
--this.lastSheetId
}
this.mappingFromCanonicalName.delete(sheet.canonicalName)
this.mappingFromId.delete(sheet.id)
}
public fetch = (sheetName: string): number => {
const sheet = this.mappingFromCanonicalName.get(canonicalize(sheetName))
if (sheet === undefined) {
throw new NoSheetWithNameError(sheetName)
}
return sheet.id
}
public get = (sheetName: string): Maybe<number> => {
return this.mappingFromCanonicalName.get(canonicalize(sheetName))?.id
}
public fetchDisplayName = (sheetId: number): string => {
return this.fetchSheetById(sheetId).displayName
}
public getDisplayName(sheetId: number): Maybe<string> {
return this.mappingFromId.get(sheetId)?.displayName
}
public* displayNames(): IterableIterator<string> {
for (const sheet of this.mappingFromCanonicalName.values()) {
yield sheet.displayName
}
}
public numberOfSheets(): number {
return this.mappingFromCanonicalName.size
}
public hasSheetWithId(sheetId: number): boolean {
return this.mappingFromId.has(sheetId)
}
public hasSheetWithName(sheetName: string): boolean {
return this.mappingFromCanonicalName.has(canonicalize(sheetName))
}
public renameSheet(sheetId: number, newDisplayName: string): Maybe<string> {
const sheet = this.fetchSheetById(sheetId)
const currentDisplayName = sheet.displayName
if (currentDisplayName === newDisplayName) {
return undefined
}
const sheetWithThisCanonicalName = this.mappingFromCanonicalName.get(canonicalize(newDisplayName))
if (sheetWithThisCanonicalName !== undefined && sheetWithThisCanonicalName.id !== sheet.id) {
throw new SheetNameAlreadyTakenError(newDisplayName)
}
const currentCanonicalName = sheet.canonicalName
this.mappingFromCanonicalName.delete(currentCanonicalName)
sheet.displayName = newDisplayName
this.store(sheet)
return currentDisplayName
}
public sheetNames(): string[] {
return Array.from(this.mappingFromId.values()).map((s) => s.displayName)
}
private store(sheet: Sheet): void {
this.mappingFromId.set(sheet.id, sheet)
this.mappingFromCanonicalName.set(sheet.canonicalName, sheet)
}
private fetchSheetById(sheetId: number): Sheet {
const sheet = this.mappingFromId.get(sheetId)
if (sheet === undefined) {
throw new NoSheetWithIdError(sheetId)
}
return sheet
}
}