@lexriver/dome 2.0.1 → 2.0.3
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/out/index.cjs +802 -0
- package/out/index.mjs +1987 -0
- package/out/src/AnimatedArray.d.ts +29 -0
- package/out/src/AnimatedTable.d.mts +2 -1
- package/out/src/AnimatedTable.d.ts +39 -0
- package/out/src/AnimatedTable.mjs +2 -1
- package/out/src/AnimatedText.d.mts +1 -1
- package/out/src/AnimatedText.d.ts +13 -0
- package/out/src/AnimatedText.mjs +1 -1
- package/out/src/Animation.d.ts +4 -0
- package/out/src/Dome.d.ts +9 -0
- package/out/src/Dome.mjs +1 -1
- package/out/src/DomeComponent.d.mts +4 -1
- package/out/src/DomeComponent.d.ts +25 -0
- package/out/src/DomeComponent.mjs +24 -3
- package/out/src/DomeManipulator.d.mts +4 -0
- package/out/src/DomeManipulator.d.ts +52 -0
- package/out/src/DomeManipulator.mjs +24 -13
- package/out/src/DomeRouter.console-test.d.ts +1 -0
- package/out/src/DomeRouter.d.ts +32 -0
- package/out/src/LongestCommonSubsequence.d.ts +15 -0
- package/out/src/concurrent-updates.test.d.mts +1 -0
- package/out/src/concurrent-updates.test.d.ts +1 -0
- package/out/src/concurrent-updates.test.mjs +203 -0
- package/out/src/index.d.ts +11 -0
- package/out/src/temp-test.d.ts +1 -0
- package/package.json +20 -3
- package/out/vitest.config.d.ts +0 -2
- package/out/vitest.config.js +0 -9
- package/src/AnimatedArray.mts +0 -74
- package/src/AnimatedTable.mts +0 -120
- package/src/AnimatedText.mts +0 -30
- package/src/Animation.mts +0 -4
- package/src/Dome.mts +0 -346
- package/src/DomeComponent.mts +0 -63
- package/src/DomeManipulator.mts +0 -380
- package/src/DomeRouter.console-test.mts +0 -52
- package/src/DomeRouter.mts +0 -287
- package/src/LongestCommonSubsequence.mts +0 -201
- package/src/index.mts +0 -12
- package/src/temp-test.mts +0 -23
- package/tsconfig.json +0 -59
- package/vitest.config.ts +0 -10
package/src/DomeRouter.mts
DELETED
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
import { DomeManipulator } from "./DomeManipulator.mjs"
|
|
2
|
-
|
|
3
|
-
// const filename = '[DomeRouter]'
|
|
4
|
-
|
|
5
|
-
export type RouteAction = (
|
|
6
|
-
params:{[key:string]:string|number},
|
|
7
|
-
url:string,
|
|
8
|
-
scrollToPreviousPositionAsync:()=>Promise<void>,
|
|
9
|
-
query:{[key:string]:string}
|
|
10
|
-
) => void|Promise<void>
|
|
11
|
-
|
|
12
|
-
interface Route{
|
|
13
|
-
routeSlices:string[]
|
|
14
|
-
exactMatch:boolean
|
|
15
|
-
action:RouteAction
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface HistoryUrl{
|
|
19
|
-
url:string
|
|
20
|
-
scroll:number
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export namespace DomeRouter {
|
|
24
|
-
const historyUrls:HistoryUrl[] = []
|
|
25
|
-
const scrollPositionByUrl = new Map<string, number>()
|
|
26
|
-
export let maxHistoryUrlsCount:number = 20
|
|
27
|
-
const allRoutes:Route[] = []
|
|
28
|
-
let onNotFoundAction:(()=>void)|undefined = undefined
|
|
29
|
-
|
|
30
|
-
window.addEventListener('popstate', async (e) => {
|
|
31
|
-
// on go back/forward
|
|
32
|
-
//console.log(filename, 'window.popstate event', e, 'historyUrls=', historyUrls)
|
|
33
|
-
const url = window.location.pathname
|
|
34
|
-
await executeAsync(url, getScrollPositionForUrl(url) )
|
|
35
|
-
|
|
36
|
-
await DomeManipulator.scrollToAsync({
|
|
37
|
-
pxFromTop: getScrollPositionForUrl(window.location.pathname)
|
|
38
|
-
})
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
function getScrollPositionForUrl(url:string){
|
|
42
|
-
return scrollPositionByUrl.get(url) ?? 0
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function saveScrollPositionForUrl(url:string){
|
|
46
|
-
scrollPositionByUrl.set(url, DomeManipulator.getCurrentScrollPosition())
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function saveScrollPositionForCurrentUrl(){
|
|
50
|
-
scrollPositionByUrl.set(getCurrentUrl(), DomeManipulator.getCurrentScrollPosition())
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function navigate(url:string){
|
|
54
|
-
addUrlToHistory(getCurrentUrl())
|
|
55
|
-
saveScrollPositionForCurrentUrl()
|
|
56
|
-
window.history.pushState(null, '', url)
|
|
57
|
-
executeAsync(url, 0)
|
|
58
|
-
DomeManipulator.scrollToTop()
|
|
59
|
-
// historyUrls.push()
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function goBack(){
|
|
63
|
-
window.history.go(-1)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function goForward(){
|
|
67
|
-
window.history.go(+1)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function changeUrl(url:string){
|
|
71
|
-
window.history.replaceState(null, '', url)
|
|
72
|
-
// if(historyUrls.length>0){
|
|
73
|
-
// historyUrls[historyUrls.length-1].url = url
|
|
74
|
-
// }
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function addUrlToHistory(url:string){
|
|
78
|
-
historyUrls.push({url, scroll: 0})
|
|
79
|
-
while(historyUrls.length>maxHistoryUrlsCount){
|
|
80
|
-
historyUrls.shift()
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// save scroll position to previous url
|
|
84
|
-
if(historyUrls.length>1){
|
|
85
|
-
historyUrls[historyUrls.length-2].scroll = DomeManipulator.getCurrentScrollPosition()
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// console.log('adding url to history', url)
|
|
89
|
-
// console.log('historyUrls=', historyUrls)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
export function getCurrentUrl(){
|
|
95
|
-
return window.location.pathname
|
|
96
|
-
// return historyUrls.length>0?historyUrls[historyUrls.length-1]:window.location.pathname
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* get previous page url navigated by router
|
|
101
|
-
* @param previousPageIndex 0=previousPage, 1=previousPage-1, etc
|
|
102
|
-
*/
|
|
103
|
-
export function getPreviousPageUrl(previousPageIndex:number=0):string|undefined{
|
|
104
|
-
//if(historyUrls.length==0) return undefined
|
|
105
|
-
let index = historyUrls.length-2-previousPageIndex
|
|
106
|
-
if(index >= 0 && index < historyUrls.length) return historyUrls[index].url
|
|
107
|
-
return undefined
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// export function reloadCurrentPage(addToHistory:boolean = false){
|
|
111
|
-
// const url = window.location.pathname
|
|
112
|
-
// if(addToHistory) addUrlToHistory(url)
|
|
113
|
-
// executeAsync(url, getScrollPositionForUrl(url)) // TODO: check
|
|
114
|
-
// }
|
|
115
|
-
|
|
116
|
-
export function resolveUrl(url:string = window.location.pathname, addToHistory = true){
|
|
117
|
-
if(addToHistory) addUrlToHistory(window.location.pathname)
|
|
118
|
-
executeAsync(url, getScrollPositionForUrl(url))
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export function onRoute(route:string, exactMatch:boolean, action:RouteAction){
|
|
122
|
-
if(route[0] !== '/') throw new Error('Please provide correct route. route='+route)
|
|
123
|
-
let routeSlices = getRouteSlices(route)
|
|
124
|
-
allRoutes.push({routeSlices, exactMatch, action})
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function getRouteSlices(route:string){
|
|
128
|
-
//return route.split('/').filter(x => x.length>0).map(x => decodeURIComponent(x))
|
|
129
|
-
return route.split('/').map(x => decodeURIComponent(x))
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export function onNotFound(action:()=>void){
|
|
133
|
-
onNotFoundAction = action
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Check if url matched route.
|
|
138
|
-
* example: /get-product/445345, /get-product/:productId, true ==> Map([productId:445345])
|
|
139
|
-
* example: /get-product/123, /another-route, true ==> undefined
|
|
140
|
-
* example: /articles, /articles, true ==> Map()
|
|
141
|
-
* example: /articles/some-article, /articles, false ==> Map()
|
|
142
|
-
* @param url
|
|
143
|
-
* @param route
|
|
144
|
-
* @param exactMatch
|
|
145
|
-
*/
|
|
146
|
-
export function checkUrlMatchRouteAndGetParameters(url:string, route:string, exactMatch:boolean = true):Object|undefined{
|
|
147
|
-
// this function is purely for export
|
|
148
|
-
|
|
149
|
-
const urlSlices = getRouteSlices(url)
|
|
150
|
-
const routeSlices = getRouteSlices(route)
|
|
151
|
-
if(exactMatch && routeSlices.length !== urlSlices.length) return undefined
|
|
152
|
-
// all routeSlices must match for !exactMatch
|
|
153
|
-
//const extractedParameters = new Map<string,string>()
|
|
154
|
-
const extractedParameters = {}
|
|
155
|
-
for(let i=0;i<routeSlices.length;i++){
|
|
156
|
-
let cRouteSlice = routeSlices[i]
|
|
157
|
-
let cUrlSlice = urlSlices[i] // could be undefined
|
|
158
|
-
//console.info('\t\t cRouteSlice=', cRouteSlice, 'cUrlSlice=', cUrlSlice)
|
|
159
|
-
|
|
160
|
-
if(cRouteSlice.startsWith(':')){
|
|
161
|
-
// we have a param name
|
|
162
|
-
if(cUrlSlice === undefined){
|
|
163
|
-
return undefined
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const [name, value] = parseToNameAndValue(cRouteSlice, cUrlSlice)
|
|
167
|
-
extractedParameters[name] = value
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
} else {
|
|
171
|
-
// no param name
|
|
172
|
-
if(cRouteSlice !== cUrlSlice){
|
|
173
|
-
return undefined
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
return extractedParameters
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* parse name with type or without type
|
|
182
|
-
* :quantity
|
|
183
|
-
* :quantity<number>
|
|
184
|
-
* :quantity<float>
|
|
185
|
-
* :quantity<int>
|
|
186
|
-
*
|
|
187
|
-
* @param name string that starts with `:`
|
|
188
|
-
* @param value string that contains value
|
|
189
|
-
*/
|
|
190
|
-
function parseToNameAndValue(name:string, value:string):[string,string|number]{
|
|
191
|
-
if(!name) throw new Error('no name')
|
|
192
|
-
|
|
193
|
-
// parse name with type
|
|
194
|
-
// :quantity<number>
|
|
195
|
-
// :lat<float>
|
|
196
|
-
// :count<int>
|
|
197
|
-
const haveMatch = name.match(/:(.+)<(.+)>/)
|
|
198
|
-
if(haveMatch){
|
|
199
|
-
const paramName = haveMatch[1]
|
|
200
|
-
const paramType = haveMatch[2].toLowerCase()
|
|
201
|
-
if(paramType == 'int'){
|
|
202
|
-
return [paramName, parseInt(value)]
|
|
203
|
-
|
|
204
|
-
} else if(paramType == 'float'){
|
|
205
|
-
return [paramName, parseFloat(value)]
|
|
206
|
-
|
|
207
|
-
} else if(paramType == 'number'){
|
|
208
|
-
return [paramName, Number(value)]
|
|
209
|
-
|
|
210
|
-
} else {
|
|
211
|
-
return [paramName, value]
|
|
212
|
-
}
|
|
213
|
-
} else {
|
|
214
|
-
return [name.substring(1), value]
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function parseQueryString(search:string):{[key:string]:string}{
|
|
220
|
-
const query:{[key:string]:string} = {}
|
|
221
|
-
if(!search || search[0] !== '?') return query
|
|
222
|
-
const params = new URLSearchParams(search.substring(1))
|
|
223
|
-
for(const [key, value] of params.entries()){
|
|
224
|
-
query[key] = value
|
|
225
|
-
}
|
|
226
|
-
return query
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
async function executeAsync(url:string = window.location.pathname, scrollToPosition:number){
|
|
230
|
-
const queryString = window.location.search
|
|
231
|
-
const query = parseQueryString(queryString)
|
|
232
|
-
url = url.split('?')[0] // Strip query params
|
|
233
|
-
//const url = window.location.pathname
|
|
234
|
-
const urlSlices = getRouteSlices(url)
|
|
235
|
-
// urlSlices = show, category, 345
|
|
236
|
-
let countOfFoundRoutes = 0
|
|
237
|
-
for(let route of allRoutes){
|
|
238
|
-
//console.info('\t route=', route.routeSlices, route.exactMatch)
|
|
239
|
-
// route.routeSlices = show, category, :categoryId
|
|
240
|
-
if(route.exactMatch && route.routeSlices.length != urlSlices.length) continue
|
|
241
|
-
|
|
242
|
-
// all routeSlices must match for !exactMatch
|
|
243
|
-
let matched:boolean = true
|
|
244
|
-
//let extractedParameters = new Map<string,string>()
|
|
245
|
-
const extractedParameters = {}
|
|
246
|
-
for(let i=0;i<route.routeSlices.length;i++){
|
|
247
|
-
let cRouteSlice = route.routeSlices[i]
|
|
248
|
-
let cUrlSlice = urlSlices[i] // could be undefined
|
|
249
|
-
//console.info('\t\t cRouteSlice=', cRouteSlice, 'cUrlSlice=', cUrlSlice)
|
|
250
|
-
|
|
251
|
-
if(cRouteSlice && typeof cRouteSlice === 'string' && cRouteSlice.startsWith(':')){
|
|
252
|
-
// we have a param name
|
|
253
|
-
if(cUrlSlice === undefined){
|
|
254
|
-
matched = false
|
|
255
|
-
continue
|
|
256
|
-
}
|
|
257
|
-
// we have some variable, save it
|
|
258
|
-
const [name, value] = parseToNameAndValue(cRouteSlice, cUrlSlice)
|
|
259
|
-
extractedParameters[name] = value
|
|
260
|
-
|
|
261
|
-
} else {
|
|
262
|
-
// no param name
|
|
263
|
-
if(cRouteSlice !== cUrlSlice){
|
|
264
|
-
matched = false
|
|
265
|
-
continue
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
if(matched){
|
|
270
|
-
countOfFoundRoutes++
|
|
271
|
-
//console.log('DomeRouter', 'executeAsync', url, route, extractedParameters)
|
|
272
|
-
await route.action(extractedParameters, url, async () => {
|
|
273
|
-
await DomeManipulator.scrollToAsync({
|
|
274
|
-
pxFromTop: scrollToPosition
|
|
275
|
-
})
|
|
276
|
-
}, query)
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
if(countOfFoundRoutes==0 && onNotFoundAction){
|
|
280
|
-
//console.log('DomeRouter', 'onNotFoundAction()')
|
|
281
|
-
onNotFoundAction()
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
export module LongestCommonSubsequence {
|
|
2
|
-
// https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-common-subsequence
|
|
3
|
-
export function getLongestCommonSubsequence(set1: string[], set2: string[]) {
|
|
4
|
-
// Init LCS matrix.
|
|
5
|
-
const lcsMatrix = Array(set2.length + 1).fill(null).map(() => Array(set1.length + 1).fill(null));
|
|
6
|
-
|
|
7
|
-
// Fill first row with zeros.
|
|
8
|
-
for (let columnIndex = 0; columnIndex <= set1.length; columnIndex += 1) {
|
|
9
|
-
lcsMatrix[0][columnIndex] = 0;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// Fill first column with zeros.
|
|
13
|
-
for (let rowIndex = 0; rowIndex <= set2.length; rowIndex += 1) {
|
|
14
|
-
lcsMatrix[rowIndex][0] = 0;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Fill rest of the column that correspond to each of two strings.
|
|
18
|
-
for (let rowIndex = 1; rowIndex <= set2.length; rowIndex += 1) {
|
|
19
|
-
for (let columnIndex = 1; columnIndex <= set1.length; columnIndex += 1) {
|
|
20
|
-
if (set1[columnIndex - 1] === set2[rowIndex - 1]) {
|
|
21
|
-
lcsMatrix[rowIndex][columnIndex] = lcsMatrix[rowIndex - 1][columnIndex - 1] + 1;
|
|
22
|
-
} else {
|
|
23
|
-
lcsMatrix[rowIndex][columnIndex] = Math.max(
|
|
24
|
-
lcsMatrix[rowIndex - 1][columnIndex],
|
|
25
|
-
lcsMatrix[rowIndex][columnIndex - 1],
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Calculate LCS based on LCS matrix.
|
|
32
|
-
if (!lcsMatrix[set2.length][set1.length]) {
|
|
33
|
-
// If the length of largest common string is zero then return empty string.
|
|
34
|
-
return [''];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const longestSequence:string[] = [];
|
|
38
|
-
let columnIndex = set1.length;
|
|
39
|
-
let rowIndex = set2.length;
|
|
40
|
-
|
|
41
|
-
while (columnIndex > 0 || rowIndex > 0) {
|
|
42
|
-
if (set1[columnIndex - 1] === set2[rowIndex - 1]) {
|
|
43
|
-
// Move by diagonal left-top.
|
|
44
|
-
longestSequence.unshift(set1[columnIndex - 1]);
|
|
45
|
-
columnIndex -= 1;
|
|
46
|
-
rowIndex -= 1;
|
|
47
|
-
} else if (lcsMatrix[rowIndex][columnIndex] === lcsMatrix[rowIndex][columnIndex - 1]) {
|
|
48
|
-
// Move left.
|
|
49
|
-
columnIndex -= 1;
|
|
50
|
-
} else {
|
|
51
|
-
// Move up.
|
|
52
|
-
rowIndex -= 1;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return longestSequence;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function getPatch({ oldArray, newArray, onRemove, onAdd }: {
|
|
60
|
-
oldArray: string[]
|
|
61
|
-
newArray: string[]
|
|
62
|
-
onRemove: (index: number, item: string) => void
|
|
63
|
-
onAdd: (index: number, item: string) => void
|
|
64
|
-
}){
|
|
65
|
-
const lcsArray = getLongestCommonSubsequence(oldArray, newArray)
|
|
66
|
-
|
|
67
|
-
let countOfOperations = 0
|
|
68
|
-
|
|
69
|
-
// console.log('oldArray=', oldArray.join(' '))
|
|
70
|
-
// console.log('newArray=', newArray.join(' '))
|
|
71
|
-
// console.log('lcsArray=', lcsArray.join(' '))
|
|
72
|
-
|
|
73
|
-
// old: A B B B C
|
|
74
|
-
// new: X X B B B B C
|
|
75
|
-
// lcs: B B B C
|
|
76
|
-
|
|
77
|
-
//let lcsStartIndexForOld = 0
|
|
78
|
-
//let lcsStartIndexForNew = 0
|
|
79
|
-
let lcsIndex = 0
|
|
80
|
-
//let newIndex = 0
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
for(let oldIndex = 0; oldIndex < oldArray.length; oldIndex++){
|
|
84
|
-
let oldItem = oldArray[oldIndex]
|
|
85
|
-
//let oldItemInLcs = itemInArray(oldItem, lcsArray, lcsStartIndexForOld)
|
|
86
|
-
let oldItemInLcs = lcsArray[lcsIndex] == oldItem
|
|
87
|
-
//console.log('oldIndex=', oldIndex, 'oldItem=', oldItem, 'in LCS=', oldItemInLcs)
|
|
88
|
-
if(oldItemInLcs){
|
|
89
|
-
//lcsStartIndexForOld++
|
|
90
|
-
lcsIndex++
|
|
91
|
-
// so we must keep this element
|
|
92
|
-
//continue
|
|
93
|
-
} else {
|
|
94
|
-
onRemove(oldIndex-countOfOperations, oldItem)
|
|
95
|
-
//indexForOperation++
|
|
96
|
-
countOfOperations++
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
lcsIndex = 0
|
|
101
|
-
|
|
102
|
-
for(let newIndex = 0; newIndex < newArray.length; newIndex++){
|
|
103
|
-
let newItem = newArray[newIndex]
|
|
104
|
-
//let newItemInLcs = itemInArray(newItem, lcsArray, lcsStartIndexForNew)
|
|
105
|
-
let newItemInLcs = lcsArray[lcsIndex] == newItem
|
|
106
|
-
if(newItemInLcs){
|
|
107
|
-
lcsIndex++
|
|
108
|
-
//lcsStartIndexForNew++
|
|
109
|
-
//keep
|
|
110
|
-
} else {
|
|
111
|
-
onAdd(newIndex, newItem)
|
|
112
|
-
countOfOperations++
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return countOfOperations
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export function getPatchOrdered({ oldArray, newArray, onRemove, onAdd }: {
|
|
123
|
-
oldArray: string[]
|
|
124
|
-
newArray: string[]
|
|
125
|
-
onRemove: (index: number, item: string) => void
|
|
126
|
-
onAdd: (index: number, item: string) => void
|
|
127
|
-
}){
|
|
128
|
-
|
|
129
|
-
const lcsArray = getLongestCommonSubsequence(oldArray, newArray)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
//let countOfOperations = 0
|
|
134
|
-
|
|
135
|
-
// console.log('oldArray=', oldArray.join(' '))
|
|
136
|
-
// console.log('newArray=', newArray.join(' '))
|
|
137
|
-
// console.log('lcsArray=', lcsArray.join(' '))
|
|
138
|
-
|
|
139
|
-
// old: A B B B C
|
|
140
|
-
// new: X X B B B B C
|
|
141
|
-
// lcs: B B B C
|
|
142
|
-
|
|
143
|
-
let lcsIndexForOld = 0
|
|
144
|
-
let lcsIndexForNew = 0
|
|
145
|
-
//let lcsIndex = 0
|
|
146
|
-
let oldIndex = 0
|
|
147
|
-
let newIndex = 0
|
|
148
|
-
let countOfRemoveOperations = 0
|
|
149
|
-
let countOfAddOperations = 0
|
|
150
|
-
let indexForOperation = 0
|
|
151
|
-
|
|
152
|
-
while(oldIndex < oldArray.length || newIndex < newArray.length){
|
|
153
|
-
while(oldIndex < oldArray.length){
|
|
154
|
-
let oldItem = oldArray[oldIndex]
|
|
155
|
-
//let oldItemInLcs = itemInArray(oldItem, lcsArray, lcsStartIndexForOld)
|
|
156
|
-
let oldItemInLcs = lcsArray[lcsIndexForOld] == oldItem
|
|
157
|
-
//console.log('oldItem', oldIndex, oldItem, oldItemInLcs)
|
|
158
|
-
if(oldItemInLcs){
|
|
159
|
-
|
|
160
|
-
//lcsStartIndexForNew++
|
|
161
|
-
//lcsStartIndexForOld++
|
|
162
|
-
lcsIndexForOld++
|
|
163
|
-
//indexForOperation++
|
|
164
|
-
oldIndex++
|
|
165
|
-
break
|
|
166
|
-
} else {
|
|
167
|
-
//onRemove(oldIndex-countOfRemoveOperations, oldItem)
|
|
168
|
-
onRemove(indexForOperation, oldItem)
|
|
169
|
-
countOfRemoveOperations++
|
|
170
|
-
oldIndex++
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
while(newIndex < newArray.length){
|
|
175
|
-
let newItem = newArray[newIndex]
|
|
176
|
-
//let newItemInLcs = itemInArray(newItem, lcsArray, lcsStartIndexForNew)
|
|
177
|
-
let newItemInLcs = lcsArray[lcsIndexForNew] == newItem
|
|
178
|
-
//console.log('newItem', oldIndex, newItem, newItemInLcs)
|
|
179
|
-
if(newItemInLcs){
|
|
180
|
-
//lcsStartIndexForNew++
|
|
181
|
-
lcsIndexForNew++
|
|
182
|
-
indexForOperation++
|
|
183
|
-
newIndex++
|
|
184
|
-
break
|
|
185
|
-
} else {
|
|
186
|
-
onAdd(indexForOperation, newItem)
|
|
187
|
-
indexForOperation++
|
|
188
|
-
countOfAddOperations++
|
|
189
|
-
newIndex++
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// console.log('countOf(+)operations', countOfAddOperations)
|
|
196
|
-
// console.log('countOf(-)operations', countOfRemoveOperations)
|
|
197
|
-
return countOfAddOperations+countOfRemoveOperations
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
}
|
package/src/index.mts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export * from '@lexriver/async'
|
|
2
|
-
export * from '@lexriver/data-types'
|
|
3
|
-
export * from '@lexriver/observable'
|
|
4
|
-
export * from '@lexriver/type-event'
|
|
5
|
-
export * from './AnimatedArray.mjs'
|
|
6
|
-
export * from './AnimatedTable.mjs'
|
|
7
|
-
export * from './AnimatedText.mjs'
|
|
8
|
-
export * from './Dome.mjs'
|
|
9
|
-
export * from './DomeComponent.mjs'
|
|
10
|
-
export * from './DomeManipulator.mjs'
|
|
11
|
-
export * from './DomeRouter.console-test.mjs'
|
|
12
|
-
|
package/src/temp-test.mts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { LongestCommonSubsequence } from "./LongestCommonSubsequence.mjs"
|
|
2
|
-
|
|
3
|
-
let oldArray = "ABCD".split('')
|
|
4
|
-
let newArray = "AXYZBCD345".split('')
|
|
5
|
-
const countOfOperations = LongestCommonSubsequence.getPatchOrdered({
|
|
6
|
-
oldArray: [...oldArray],
|
|
7
|
-
newArray: newArray,
|
|
8
|
-
onRemove: (index, item) => {
|
|
9
|
-
console.log('-', item, index)
|
|
10
|
-
oldArray.splice(index,1)
|
|
11
|
-
},
|
|
12
|
-
onAdd: (index, item) => {
|
|
13
|
-
console.log('+', item, index)
|
|
14
|
-
oldArray.splice(index,0,item)
|
|
15
|
-
}
|
|
16
|
-
})
|
|
17
|
-
console.log('expecting equal', oldArray, newArray)
|
|
18
|
-
console.log('countOfOperations=', countOfOperations)
|
|
19
|
-
//expect(oldArray).toEqual(newArray)
|
|
20
|
-
// console.log('result oldArray=', oldArray)
|
|
21
|
-
// console.log('result nweArray=', newArray)
|
|
22
|
-
|
|
23
|
-
|
package/tsconfig.json
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
/* Basic Options */
|
|
4
|
-
//"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
|
|
5
|
-
// "target": "es5",
|
|
6
|
-
//"target":"ESNext",
|
|
7
|
-
"target": "ESNext",
|
|
8
|
-
"moduleResolution": "NodeNext",
|
|
9
|
-
"module": "NodeNext",
|
|
10
|
-
//"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
|
11
|
-
// "lib": [], /* Specify library files to be included in the compilation. */
|
|
12
|
-
// "allowJs": true, /* Allow javascript files to be compiled. */
|
|
13
|
-
// "checkJs": true, /* Report errors in .js files. */
|
|
14
|
-
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
|
15
|
-
"declaration": true, /* Generates corresponding '.d.ts' file. */
|
|
16
|
-
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
|
17
|
-
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
|
18
|
-
// "outFile": "./", /* Concatenate and emit output to single file. */
|
|
19
|
-
"outDir": "./out", /* Redirect output structure to the directory. */
|
|
20
|
-
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
|
21
|
-
// "composite": true, /* Enable project compilation */
|
|
22
|
-
// "removeComments": true, /* Do not emit comments to output. */
|
|
23
|
-
// "noEmit": true, /* Do not emit outputs. */
|
|
24
|
-
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
|
25
|
-
"downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
|
26
|
-
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
|
27
|
-
/* Strict Type-Checking Options */
|
|
28
|
-
"strict": true, /* Enable all strict type-checking options. */
|
|
29
|
-
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
|
|
30
|
-
// "strictNullChecks": true, /* Enable strict null checks. */
|
|
31
|
-
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
|
32
|
-
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
|
33
|
-
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
|
34
|
-
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
|
35
|
-
/* Additional Checks */
|
|
36
|
-
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
|
37
|
-
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
|
38
|
-
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
|
39
|
-
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
|
40
|
-
/* Module Resolution Options */
|
|
41
|
-
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
|
42
|
-
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
|
43
|
-
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
|
44
|
-
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
|
45
|
-
// "typeRoots": [], /* List of folders to include type definitions from. */
|
|
46
|
-
// "types": [], /* Type declaration files to be included in compilation. */
|
|
47
|
-
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
|
48
|
-
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
|
49
|
-
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
|
50
|
-
/* Source Map Options */
|
|
51
|
-
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
|
52
|
-
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
|
53
|
-
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
|
54
|
-
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
|
55
|
-
/* Experimental Options */
|
|
56
|
-
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
|
57
|
-
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
|
58
|
-
},
|
|
59
|
-
}
|