kireji 0.2.0 → 0.3.0
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/package.json +1 -1
- package/src/app/kireji/editor/tab-group/build.js +1 -6
- package/src/app/kireji/editor/tab-group/factor-get-permutation.js +1 -1
- package/src/app/kireji/editor/tab-group/part.css +30 -24
- package/src/app/kireji/editor/tab-group/routeID-distribute.js +7 -24
- package/src/app/kireji/editor/tab-group/routeID-get-permutation.js +2 -3
- package/src/app/kireji/editor/tab-group/type.d.ts +0 -4
- package/src/app/kireji/static.css +2 -2
- package/src/build.js +112 -85
- package/src/build.js_.js +1 -8
- package/src/parts/abstract/scroller/view-add.js +11 -0
- package/src/parts/core/client/async-install.js +1 -1
- package/src/parts/core/hot-keys/combo_.js +2 -0
- package/src/parts/core/server/sync-install.js +3 -3
- package/src/parts/desktop/era/modern/part.css +1 -1
- package/src/parts/desktop/icons/point.js +1 -1
- package/src/point.js +1 -1
- package/src/type.d.ts +13 -3
package/package.json
CHANGED
|
@@ -3,10 +3,7 @@ const tabBitDepths = [0n, 0n]
|
|
|
3
3
|
const tabOffsets = [0n]
|
|
4
4
|
const permutationSizes = [1n]
|
|
5
5
|
const payloadSizes = [1n]
|
|
6
|
-
const
|
|
7
|
-
const subjectCount = BigInt(allParts.reduce((subjectCount, part, i) =>
|
|
8
|
-
partOffsets[i + 2] = subjectCount + part.filenames.length, allParts.length
|
|
9
|
-
))
|
|
6
|
+
const subjectCount = BigInt(allSubjects.length)
|
|
10
7
|
const maxTabCount = subjectCount
|
|
11
8
|
const LSB = []
|
|
12
9
|
const powerFloor = 2n ** BigInt(subjectCount.toString(2).length - 1)
|
|
@@ -63,8 +60,6 @@ tabGroup.define({
|
|
|
63
60
|
tabBitDepths: { value: tabBitDepths },
|
|
64
61
|
permutationSizes: { value: permutationSizes },
|
|
65
62
|
payloadSizes: { value: payloadSizes },
|
|
66
|
-
partOffsets: { value: partOffsets },
|
|
67
|
-
subjectCount: { value: subjectCount },
|
|
68
63
|
maxTabCount: { value: maxTabCount },
|
|
69
64
|
previousPart: { value: null, writable: true },
|
|
70
65
|
tree: { value: null, writable: true },
|
|
@@ -46,16 +46,7 @@
|
|
|
46
46
|
display: none;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
position: fixed;
|
|
51
|
-
pointer-events: none;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
#kireji_app tab-[data-drag-preview] .close-tab {
|
|
55
|
-
display: none;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
#kireji_app tab- {
|
|
49
|
+
tab- {
|
|
59
50
|
height: fit-content;
|
|
60
51
|
white-space: pre;
|
|
61
52
|
text-overflow: ellipsis;
|
|
@@ -71,12 +62,12 @@
|
|
|
71
62
|
line-height: var(--tab-line-height);
|
|
72
63
|
}
|
|
73
64
|
|
|
74
|
-
|
|
65
|
+
tab- img {
|
|
75
66
|
height: var(--tab-icon-size);
|
|
76
67
|
margin: calc((var(--tab-group-height) - var(--tab-icon-size)) / 2) 0;
|
|
77
68
|
}
|
|
78
69
|
|
|
79
|
-
|
|
70
|
+
tab- .tab-button {
|
|
80
71
|
font-size: var(--default-font-size);
|
|
81
72
|
font-weight: 400;
|
|
82
73
|
height: unset;
|
|
@@ -105,6 +96,20 @@
|
|
|
105
96
|
z-index: 999;
|
|
106
97
|
}
|
|
107
98
|
|
|
99
|
+
tab-[data-drag-preview] {
|
|
100
|
+
width: min-content;
|
|
101
|
+
pointer-events: none;
|
|
102
|
+
position: fixed;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
tab-[data-drag-preview] .tab-button {
|
|
106
|
+
padding-right: calc(var(--spacing) / 1.5);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
tab-[data-drag-preview] .close-tab {
|
|
110
|
+
display: none;
|
|
111
|
+
}
|
|
112
|
+
|
|
108
113
|
#kireji_app tab-[data-drop-target="after"]::before {
|
|
109
114
|
right: -1px;
|
|
110
115
|
}
|
|
@@ -156,7 +161,7 @@ body.modern.light #kireji_app tab-:is([data-active], :not([data-active]):hover)
|
|
|
156
161
|
background-color: var(--bg-light-est);
|
|
157
162
|
}
|
|
158
163
|
|
|
159
|
-
body.modern
|
|
164
|
+
body.modern tab- {
|
|
160
165
|
box-shadow:
|
|
161
166
|
inset 0 -2px 0 -1px var(--bg-un-mode),
|
|
162
167
|
inset 0 2px 0 -1px var(--bg-un-mode),
|
|
@@ -169,7 +174,12 @@ body.modern #kireji_app tab-[data-active] {
|
|
|
169
174
|
inset -2px 0 0 -1px var(--bg-un-mode);
|
|
170
175
|
}
|
|
171
176
|
|
|
172
|
-
body.modern
|
|
177
|
+
body.modern>tab-[data-drag-preview] {
|
|
178
|
+
box-shadow: inset 0 0 0 1px var(--bg-un-mode);
|
|
179
|
+
background-color: var(--bg-light-est);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
body.modern tab- .tab-button {
|
|
173
183
|
line-height: var(--tab-group-height);
|
|
174
184
|
}
|
|
175
185
|
|
|
@@ -179,10 +189,6 @@ body.modern #kireji_app tab- .tab-path {
|
|
|
179
189
|
display: inline-block;
|
|
180
190
|
}
|
|
181
191
|
|
|
182
|
-
body.modern #kireji_app tab-[data-drag-preview] .tab-path {
|
|
183
|
-
display: none;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
192
|
body.vintage #kireji_app #tab-group {
|
|
187
193
|
height: calc(4px + var(--tab-group-height));
|
|
188
194
|
background: transparent;
|
|
@@ -222,11 +228,11 @@ body.vintage #kireji_app tab-[data-active] {
|
|
|
222
228
|
z-index: 2;
|
|
223
229
|
}
|
|
224
230
|
|
|
225
|
-
body.vintage #kireji_app tab- .tab-path {
|
|
231
|
+
/*body.vintage #kireji_app tab- .tab-path {
|
|
226
232
|
display: none;
|
|
227
|
-
}
|
|
233
|
+
}*/
|
|
228
234
|
|
|
229
|
-
body.vintage
|
|
235
|
+
body.vintage tab-:not([data-active]) {
|
|
230
236
|
height: var(--tab-group-height);
|
|
231
237
|
position: relative;
|
|
232
238
|
top: 2px;
|
|
@@ -239,7 +245,7 @@ body.vintage #kireji_app tab-[data-active] .tab-button {
|
|
|
239
245
|
padding-left: calc(var(--spacing) / 1.5 + 2px);
|
|
240
246
|
}
|
|
241
247
|
|
|
242
|
-
body.vintage
|
|
248
|
+
body.vintage tab- .tab-button {
|
|
243
249
|
padding-right: calc(var(--tab-group-height) + 8px);
|
|
244
250
|
border-top-left-radius: 2px;
|
|
245
251
|
border-top-right-radius: 2px;
|
|
@@ -251,7 +257,7 @@ body.vintage #kireji_app tab- .tab-button {
|
|
|
251
257
|
inset -3px 0 0 -1px var(--bg-dark);
|
|
252
258
|
}
|
|
253
259
|
|
|
254
|
-
body.dark.vintage
|
|
260
|
+
body.dark.vintage tab- .tab-button {
|
|
255
261
|
box-shadow:
|
|
256
262
|
inset -2px 0 0 -1px black,
|
|
257
263
|
inset 1px 1px 0 0 var(--bg-light-er),
|
|
@@ -279,7 +285,7 @@ body.vintage #kireji_app tab-[data-active] .tab-button:focus::after {
|
|
|
279
285
|
--inset: 4px;
|
|
280
286
|
}
|
|
281
287
|
|
|
282
|
-
body.vintage
|
|
288
|
+
body.vintage>tab-[data-drag-preview] .tab-button {
|
|
283
289
|
box-shadow: inset 0 0 0 1px black;
|
|
284
290
|
}
|
|
285
291
|
|
|
@@ -37,7 +37,7 @@ if (numberOfTabsOpen !== tabGroup.openTabs.length || tabGroup.permutationRouteID
|
|
|
37
37
|
tabGroup.tree = new tabGroup.FenwickTree()
|
|
38
38
|
|
|
39
39
|
const indexOfLastOpenTab = numberOfTabsOpen - 1n
|
|
40
|
-
const indexOfLastPossibleTabSubject =
|
|
40
|
+
const indexOfLastPossibleTabSubject = BigInt(allSubjects.length) - 1n
|
|
41
41
|
|
|
42
42
|
for (let currentTabIndex = 0n; currentTabIndex < numberOfTabsOpen; currentTabIndex++) {
|
|
43
43
|
|
|
@@ -56,29 +56,12 @@ if (numberOfTabsOpen !== tabGroup.openTabs.length || tabGroup.permutationRouteID
|
|
|
56
56
|
const payload = payloadRouteID % tabGroup.payloadCardinality
|
|
57
57
|
payloadRouteID /= tabGroup.payloadCardinality
|
|
58
58
|
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
payload
|
|
66
|
-
}
|
|
67
|
-
} else {
|
|
68
|
-
|
|
69
|
-
// The index is among the later planes, indicating a specific file defined on a specific part.
|
|
70
|
-
for (let indexOfPlane = 1; indexOfPlane <= allParts.length; indexOfPlane++) {
|
|
71
|
-
const nextPlaneIndex = indexOfPlane + 1
|
|
72
|
-
if (nextPlaneIndex > allParts.length || trueIndexOfActiveTabSubject < tabGroup.partOffsets[nextPlaneIndex]) {
|
|
73
|
-
const indexOfOwningPart = indexOfPlane - 1
|
|
74
|
-
const part = allParts[indexOfOwningPart]
|
|
75
|
-
const firstIndexOfCurrentPlane = tabGroup.partOffsets[indexOfPlane]
|
|
76
|
-
const indexOfSubjectWithinCurrentPlane = Number(trueIndexOfActiveTabSubject) - firstIndexOfCurrentPlane
|
|
77
|
-
const filename = part.filenames[indexOfSubjectWithinCurrentPlane]
|
|
78
|
-
tabGroup.openTabs[currentTabIndex] = { part, filename, payload }
|
|
79
|
-
break
|
|
80
|
-
}
|
|
81
|
-
}
|
|
59
|
+
// Match the subject index with the actual subject.
|
|
60
|
+
const [host, filename] = allSubjects[Number(trueIndexOfActiveTabSubject)]
|
|
61
|
+
tabGroup.openTabs[currentTabIndex] = {
|
|
62
|
+
part: partsByHost[host],
|
|
63
|
+
filename,
|
|
64
|
+
payload
|
|
82
65
|
}
|
|
83
66
|
}
|
|
84
67
|
|
|
@@ -7,10 +7,9 @@ tabGroup.tree = new tabGroup.FenwickTree()
|
|
|
7
7
|
let permutationRouteID = 0n
|
|
8
8
|
for (let currentTabIndex = 0n; currentTabIndex < numberOfTabsOpen; currentTabIndex++) {
|
|
9
9
|
|
|
10
|
-
//
|
|
10
|
+
// Get the absolute tab subject index.
|
|
11
11
|
const { part, filename } = TABS[Number(currentTabIndex)]
|
|
12
|
-
const
|
|
13
|
-
const trueIndexOfActiveTabSubject = BigInt(filename ? tabGroup.partOffsets[index + 1] + part.filenames.indexOf(filename) : index)
|
|
12
|
+
const trueIndexOfActiveTabSubject = BigInt(subjectIndices.get(part.host + (filename ? "/" + filename : "")))
|
|
14
13
|
|
|
15
14
|
// Use the Fenwick tree to obtain the availability-based index of the tab subject in the list of remaining subjects.
|
|
16
15
|
const availabilityIndexOfActiveTabSubject = tabGroup.tree.query(trueIndexOfActiveTabSubject - 1n)
|
|
@@ -57,10 +57,6 @@ declare interface IKirejiAppTabGroup
|
|
|
57
57
|
readonly activeTabIndex: number
|
|
58
58
|
/** The index of the preview tab, if one exists. The preview tab is the tab which can be replaced when opening a new tab. */
|
|
59
59
|
readonly previewTabIndex?: number
|
|
60
|
-
/** The array of memoized offset route IDs corresponding to the start of each part's filename plane. */
|
|
61
|
-
readonly partOffsets: number[]
|
|
62
|
-
/** The total number of tab subjects available - the number of _different_ filenames and part summaries that can be the focus of their own tab (regardless of the maximum number of tabs which can be open at once). */
|
|
63
|
-
readonly subjectCount: bigint
|
|
64
60
|
/** A data type which can be used to performantly rank and unrank permutation indices. */
|
|
65
61
|
readonly FenwickTree: typeof FenwickTree
|
|
66
62
|
}
|
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
--sidebar-width: calc(var(--tool-bar-width) + var(--sidebar-view-width));
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
body.modern
|
|
12
|
+
body.modern {
|
|
13
13
|
--tab-group-height: calc(var(--tab-line-height) + var(--spacing) / 1.5);
|
|
14
14
|
--tab-line-height: 26px;
|
|
15
15
|
--crumbs-height: 26px;
|
|
16
16
|
--tab-icon-size: 20px;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
body.vintage
|
|
19
|
+
body.vintage {
|
|
20
20
|
--tab-group-height: calc(var(--tab-line-height) + 2px);
|
|
21
21
|
--tab-line-height: 20px;
|
|
22
22
|
--crumbs-height: 20px;
|
package/src/build.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
function ƒ(_) {
|
|
2
|
+
function ƒ(_, compressedSubjectOrigins) {
|
|
3
3
|
|
|
4
4
|
// Initialization
|
|
5
5
|
const
|
|
6
6
|
environment = globalThis.constructor === globalThis.Window ? "client" : globalThis.constructor === globalThis.ServiceWorkerGlobalScope ? "worker" : (
|
|
7
7
|
Object.defineProperty(_, "$", { value: (f => x => f(x).toString().trim())(require("child_process").execSync) }),
|
|
8
8
|
_.command = process.argv[2] || "help",
|
|
9
|
-
_.local = _.command === "dev",
|
|
9
|
+
_.local = _.command === "dev" ? "1" : "0",
|
|
10
10
|
require.main === module && (
|
|
11
11
|
_.branch = _.$("git rev-parse --abbrev-ref HEAD").toString().trim(),
|
|
12
12
|
_.gitSHA = _.$("git rev-parse HEAD").toString().trim(),
|
|
13
|
-
_.version = (([M, m, p], c) => _.local ? +M && c === "major" ? `${++M}.0.0` : c === "minor" || (!+M && c === "major") ? `${M}.${++m}.0` : `${M}.${m}.${++p}` : `${M}.${m}.${p}`)(_.$("git log -1 --pretty=%s").toString().match(/^\s*(\d+\.\d+\.\d+)/)[1].split("."), _.change),
|
|
13
|
+
_.version = (([M, m, p], c) => +_.local ? +M && c === "major" ? `${++M}.0.0` : c === "minor" || (!+M && c === "major") ? `${M}.${++m}.0` : `${M}.${m}.${++p}` : `${M}.${m}.${p}`)(_.$("git log -1 --pretty=%s").toString().match(/^\s*(\d+\.\d+\.\d+)/)[1].split("."), _.change),
|
|
14
14
|
_.modified = _.$('git show -s --format=%ci HEAD').toString().trim(),
|
|
15
|
-
_.ETag = `"${_.version}.${_.gitSHA.slice(0, 7)}${_.local ? ("." + Math.random()).slice(2, 10) : ""}"`,
|
|
15
|
+
_.ETag = `"${_.version}.${_.gitSHA.slice(0, 7)}${+_.local ? ("." + Math.random()).slice(2, 10) : ""}"`,
|
|
16
16
|
_.name = __dirname.split(/[\\/]/).filter(Boolean).at(-4)
|
|
17
17
|
),
|
|
18
18
|
"node"
|
|
19
19
|
),
|
|
20
|
-
production = _.branch === "main" && environment !== "node" && !_.local,
|
|
20
|
+
production = _.branch === "main" && environment !== "node" && !(+_.local),
|
|
21
21
|
welcomeMessage = `
|
|
22
22
|
▌ ▘ ▘▘ ${_.name}
|
|
23
23
|
k = ▙▘▌▛▘█▌ ▌▌ ${_.branch}
|
|
@@ -132,6 +132,9 @@ function ƒ(_) {
|
|
|
132
132
|
pathRadix = "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_0",
|
|
133
133
|
encodeSegment = routeID => {
|
|
134
134
|
|
|
135
|
+
if (typeof routeID !== "bigint")
|
|
136
|
+
throw new RangeError(`Segment encoder can only encode a bigint type (got ${typeof routeID})`)
|
|
137
|
+
|
|
135
138
|
if (routeID < 0n)
|
|
136
139
|
throw new RangeError("Segment encoder cannot encode a negative route ID.")
|
|
137
140
|
|
|
@@ -230,16 +233,41 @@ function ƒ(_) {
|
|
|
230
233
|
┊ Now booting the Kireji Web Framework ┊
|
|
231
234
|
╰┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╯
|
|
232
235
|
`)
|
|
233
|
-
|
|
236
|
+
|
|
237
|
+
const
|
|
238
|
+
bootStartTime = Date.now(),
|
|
239
|
+
allSubjects = [],
|
|
240
|
+
subjectIndices = new Map(),
|
|
241
|
+
subjectOrigins = new Map()
|
|
242
|
+
|
|
234
243
|
if (environment === "node" && require.main === module) {
|
|
244
|
+
subjectOrigins.set("", true)
|
|
245
|
+
|
|
235
246
|
const
|
|
236
|
-
stats = { fileCount: 0,
|
|
247
|
+
stats = { fileCount: 0, partCount: 0, ignoreCount: 0 },
|
|
237
248
|
{ readdirSync: readFolder, readFileSync: readFile, existsSync: exists } = require("fs"),
|
|
238
|
-
{ resolve } = require("path")
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
249
|
+
{ resolve } = require("path")
|
|
250
|
+
|
|
251
|
+
logScope(1, "Merging Configurations", configLog => {
|
|
252
|
+
for (const key in _) {
|
|
253
|
+
const value = _[key]
|
|
254
|
+
if (typeof value !== "string")
|
|
255
|
+
throw new TypeError(`Internal Error: found framework default config parameter that was not a string (typeof "${key}" === ${typeof value}).`)
|
|
256
|
+
subjectOrigins.set("/" + key, false)
|
|
257
|
+
}
|
|
258
|
+
const projectConfigPath = resolve(__dirname, "../../../src/kireji.json")
|
|
259
|
+
if (exists(projectConfigPath)) {
|
|
260
|
+
const projectConfig = require(projectConfigPath)
|
|
261
|
+
for (const key in projectConfig) {
|
|
262
|
+
const value = projectConfig[key]
|
|
263
|
+
if (typeof value !== "string")
|
|
264
|
+
throw new TypeError(`All config values in kireji.json must be strings (found typeof "${key}" === ${typeof value}).`)
|
|
265
|
+
_[key] = value
|
|
266
|
+
subjectOrigins.set("/" + key, true)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
configLog("Done.")
|
|
270
|
+
})
|
|
243
271
|
|
|
244
272
|
logScope(1, "Archiving Repository", archiveLog => {
|
|
245
273
|
let lastLogFlush = Date.now()
|
|
@@ -256,88 +284,69 @@ function ƒ(_) {
|
|
|
256
284
|
lastLogFlush = now
|
|
257
285
|
}
|
|
258
286
|
},
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
287
|
+
frameworkRoot = __dirname,
|
|
288
|
+
projectRoot = resolve(__dirname, "../../../src"),
|
|
289
|
+
readRecursive = domains => {
|
|
262
290
|
|
|
263
|
-
|
|
264
|
-
const baseEntries = exists(baseDir) ? readFolder(baseDir, { withFileTypes: true }) : []
|
|
265
|
-
const overlayEntries = exists(overlayDir) ? readFolder(overlayDir, { withFileTypes: true }) : []
|
|
291
|
+
const host = [...domains].reverse().join(".")
|
|
266
292
|
|
|
267
|
-
|
|
268
|
-
|
|
293
|
+
if (host.length > 253)
|
|
294
|
+
throw SyntaxError(`Part host would be ${host.length} characters long, exceeding the maximum host name length of 253 (${host}).`)
|
|
269
295
|
|
|
270
|
-
|
|
271
|
-
for (const entry of baseEntries)
|
|
272
|
-
unifiedEntries.set(entry.name, { entry, source: 'base' })
|
|
296
|
+
const mergedSubjects = new Map()
|
|
273
297
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
298
|
+
const frameworkPath = resolve(frameworkRoot, ...domains)
|
|
299
|
+
if (exists(frameworkPath))
|
|
300
|
+
for (const subject of readFolder(frameworkPath, { withFileTypes: true }))
|
|
301
|
+
mergedSubjects.set(subject.name, { subject, path: frameworkPath })
|
|
277
302
|
|
|
278
|
-
const
|
|
303
|
+
const projectPath = resolve(projectRoot, ...domains)
|
|
304
|
+
if (exists(projectPath))
|
|
305
|
+
for (const subject of readFolder(projectPath, { withFileTypes: true }))
|
|
306
|
+
mergedSubjects.set(subject.name, { subject, path: projectPath })
|
|
279
307
|
|
|
280
|
-
|
|
281
|
-
// Ignore logic (TS files, hidden files, etc)
|
|
282
|
-
if (itemName.startsWith(".") || itemName === "Icon" || (!host && itemName === "build.js") || itemName.endsWith(".ts")) {
|
|
283
|
-
bufferLog(4, "".padEnd(depth, " ") + `⬚ ${itemName.padEnd(20, " ")} - ignored`)
|
|
284
|
-
continue
|
|
285
|
-
}
|
|
308
|
+
const part = domains.length ? {} : _
|
|
286
309
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
} else if (entry.isFile()) {
|
|
307
|
-
// Prioritize overlay file path, fallback to base
|
|
308
|
-
const actualPath = (source === 'overlay') ? nextOverlay : nextBase
|
|
309
|
-
filenames.push([itemName, actualPath])
|
|
310
|
+
for (const [itemName, { subject, path }] of mergedSubjects)
|
|
311
|
+
if (itemName.startsWith(".") || itemName === "Icon" || (!host && itemName === "build.js") || itemName.endsWith(".ts")) {
|
|
312
|
+
stats.ignoreCount++
|
|
313
|
+
bufferLog(4, "".padEnd(domains.length, " ") + `⬚ ${itemName.padEnd(20, " ")} - ignored`)
|
|
314
|
+
} else if (subject.isDirectory()) {
|
|
315
|
+
stats.partCount++
|
|
316
|
+
bufferLog(2, "".padEnd(domains.length, " ") + `▼ ${itemName}/`)
|
|
317
|
+
subjectOrigins.set(itemName + (host ? "." + host : ""), path === projectPath)
|
|
318
|
+
part[itemName] = readRecursive([...domains, itemName])
|
|
319
|
+
} else if (subject.isFile()) {
|
|
320
|
+
stats.fileCount++
|
|
321
|
+
const isBinary = itemName.endsWith(".png") || itemName.endsWith(".gif")
|
|
322
|
+
bufferLog(3, "".padEnd(domains.length, " ") + `${isBinary ? "▣" : "≡"} ${itemName}`)
|
|
323
|
+
subjectOrigins.set(host + "/" + itemName, path === projectPath)
|
|
324
|
+
part[itemName] = readFile(resolve(path, itemName), isBinary ? "base64" : "utf-8")
|
|
325
|
+
} else {
|
|
326
|
+
stats.ignoreCount++
|
|
327
|
+
bufferLog(4, "".padEnd(domains.length, " ") + `⬚ ${itemName.padEnd(20, " ")} - ignored (exotic type)`)
|
|
310
328
|
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// File processing (remains largely the same, but uses the prioritized path)
|
|
314
|
-
for (const [filename, filePath] of filenames) {
|
|
315
|
-
const isBinary = filename.endsWith("png") || filename.endsWith("gif")
|
|
316
|
-
const content = readFile(filePath, isBinary ? "base64" : "utf-8")
|
|
317
|
-
|
|
318
|
-
part[filename] = content
|
|
319
|
-
stats.fileCount++
|
|
320
|
-
bufferLog(3, "".padEnd(depth, " ") + `${isBinary ? "▣" : "≡"} ${filename}`)
|
|
321
|
-
}
|
|
322
329
|
|
|
323
|
-
|
|
330
|
+
return part
|
|
324
331
|
}
|
|
325
332
|
|
|
326
|
-
readRecursive(
|
|
333
|
+
readRecursive([])
|
|
327
334
|
|
|
328
335
|
if (batchedLogs.length)
|
|
329
336
|
archiveLog(batchedLogs.join("\n") + "\n")
|
|
330
337
|
|
|
331
|
-
archiveLog(`Archived in ${Date.now() -
|
|
338
|
+
archiveLog(`Archived in ${Date.now() - bootStartTime}ms`)
|
|
332
339
|
})
|
|
333
340
|
|
|
334
|
-
logScope(2, "\
|
|
341
|
+
logScope(2, "\nDomain Stats", () => {
|
|
335
342
|
logAny(2, [{
|
|
336
|
-
Parts: { Amount: stats.
|
|
343
|
+
Parts: { Amount: stats.partCount },
|
|
337
344
|
Files: { Amount: stats.fileCount },
|
|
345
|
+
Ignored: { Amount: stats.ignoreCount }
|
|
338
346
|
}], "table")
|
|
339
347
|
})
|
|
340
348
|
}
|
|
349
|
+
|
|
341
350
|
logScope(1, "\nRecursively Hydrating Parts", hydrateLog => {
|
|
342
351
|
|
|
343
352
|
class SourceMappedFile {
|
|
@@ -404,7 +413,7 @@ function ƒ(_) {
|
|
|
404
413
|
packAndMap(url) {
|
|
405
414
|
const sourceFile = this
|
|
406
415
|
const script = sourceFile.lines.join("\n")
|
|
407
|
-
return _.mapping
|
|
416
|
+
return +_.mapping
|
|
408
417
|
? script +
|
|
409
418
|
`
|
|
410
419
|
//${"#"} sourceMappingURL=data:application/json;charset=utf-8;base64,${btoaUnicode(sourceFile.getMap())}${url
|
|
@@ -474,7 +483,7 @@ function ƒ(_) {
|
|
|
474
483
|
earlyImageSources = [],
|
|
475
484
|
partsByHost = {},
|
|
476
485
|
preHydrationArchive = serialize(_),
|
|
477
|
-
|
|
486
|
+
hydratePartsRecursive = (part, domains = []) => {
|
|
478
487
|
|
|
479
488
|
let host
|
|
480
489
|
|
|
@@ -516,7 +525,9 @@ function ƒ(_) {
|
|
|
516
525
|
const extendsString = part.manifest.extends ?? "part"
|
|
517
526
|
const relativeStepsBack = extendsString.match(/\.*$/)[0].length
|
|
518
527
|
const typename = relativeStepsBack ? `${extendsString.slice(0, -relativeStepsBack)}.${domains.slice(relativeStepsBack - 1).join(".")}` : extendsString.includes(".") ? extendsString : `${extendsString}.abstract.parts`
|
|
519
|
-
prototype =
|
|
528
|
+
prototype = hydratePartsRecursive(typename)
|
|
529
|
+
if (!prototype.isAbstract)
|
|
530
|
+
throw new Error(`Hydration Error: parts can only extend abstract parts (${host} tried to extend ${prototype.host}).`)
|
|
520
531
|
Object.setPrototypeOf(part, prototype)
|
|
521
532
|
part.define({
|
|
522
533
|
isAbstract: { value: part.manifest.abstract }
|
|
@@ -662,6 +673,8 @@ function ƒ(_) {
|
|
|
662
673
|
earlyImageSources.push([part, fn.slice(6)])
|
|
663
674
|
imageSources.push([part, fn])
|
|
664
675
|
}
|
|
676
|
+
subjectIndices.set(`${host}/${fn}`, allSubjects.length)
|
|
677
|
+
allSubjects.push([host, fn])
|
|
665
678
|
}
|
|
666
679
|
for (const methodID in part.manifest)
|
|
667
680
|
if (!["extends", "abstract"].includes(methodID))
|
|
@@ -690,7 +703,7 @@ function ƒ(_) {
|
|
|
690
703
|
part.define({ [identifier]: { value: childPart } })
|
|
691
704
|
}
|
|
692
705
|
|
|
693
|
-
|
|
706
|
+
hydratePartsRecursive(childPart, [subdomain, ...domains])
|
|
694
707
|
|
|
695
708
|
childPart.define({ "..": { value: part } })
|
|
696
709
|
|
|
@@ -699,10 +712,23 @@ function ƒ(_) {
|
|
|
699
712
|
}
|
|
700
713
|
if (!part.isAbstract) instances.push(part)
|
|
701
714
|
allParts.push(part)
|
|
715
|
+
subjectIndices.set(host, allSubjects.length)
|
|
716
|
+
allSubjects.push([host])
|
|
702
717
|
})
|
|
703
718
|
|
|
704
719
|
return part
|
|
705
720
|
},
|
|
721
|
+
hydrateSubjectOrigins = () => {
|
|
722
|
+
if (environment === "node") {
|
|
723
|
+
const bits = allSubjects.map(([host, fn]) => +subjectOrigins.get(host + (fn ? "/" + fn : "")))
|
|
724
|
+
const bitString = bits.join("")
|
|
725
|
+
compressedSubjectOrigins = encodeSegment(BigInt("0b" + bitString))
|
|
726
|
+
} else {
|
|
727
|
+
const bitString = decodeSegment(compressedSubjectOrigins).toString(2).padStart(allSubjects.length, "0")
|
|
728
|
+
const bits = [...bitString]
|
|
729
|
+
allSubjects.forEach(([host, fn], index) => subjectOrigins.set(host + (fn ? "/" + fn : ""), bits[index] === "1"))
|
|
730
|
+
}
|
|
731
|
+
},
|
|
706
732
|
countAndSortInheritorsRecursive = part => {
|
|
707
733
|
if (part.totalInheritors !== undefined)
|
|
708
734
|
return part.totalInheritors
|
|
@@ -717,7 +743,8 @@ function ƒ(_) {
|
|
|
717
743
|
return totalInheritors
|
|
718
744
|
}
|
|
719
745
|
|
|
720
|
-
|
|
746
|
+
hydratePartsRecursive(_)
|
|
747
|
+
hydrateSubjectOrigins()
|
|
721
748
|
countAndSortInheritorsRecursive(_.parts.abstract.part)
|
|
722
749
|
hydrateLog(`\nParts hydrated in ${Date.now() - hydrationStartTime}ms.`)
|
|
723
750
|
|
|
@@ -752,10 +779,10 @@ function ƒ(_) {
|
|
|
752
779
|
})
|
|
753
780
|
|
|
754
781
|
logScope(1, "\nBuilding Part Instances", buildLog => {
|
|
755
|
-
const
|
|
782
|
+
const bootStartTime = Date.now()
|
|
756
783
|
for (const part of instances)
|
|
757
784
|
part.startBuild()
|
|
758
|
-
buildLog(`Parts built in ${Date.now() -
|
|
785
|
+
buildLog(`Parts built in ${Date.now() - bootStartTime}ms.`)
|
|
759
786
|
})
|
|
760
787
|
|
|
761
788
|
logScope(2, "\nLogging Part Entropy", () => {
|
|
@@ -795,7 +822,7 @@ function ƒ(_) {
|
|
|
795
822
|
|
|
796
823
|
bootLog(`
|
|
797
824
|
╭┈┈┈┈┈┈┈┈┈┈┈ BOOT SUCCEEDED ┈┈┈┈┈┈┈┈┈┈┈╮
|
|
798
|
-
┊ Booted in ${(Date.now() -
|
|
825
|
+
┊ Booted in ${(Date.now() - bootStartTime + "ms.").padEnd(27, " ")}┊
|
|
799
826
|
┊ ┊
|
|
800
827
|
┊ End of synchronous script execution. ┊
|
|
801
828
|
╰┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╯
|
|
@@ -804,12 +831,12 @@ function ƒ(_) {
|
|
|
804
831
|
}
|
|
805
832
|
|
|
806
833
|
ƒ({
|
|
807
|
-
verbosity: 1,
|
|
834
|
+
verbosity: "1",
|
|
808
835
|
// TODO: Fix source mapping bugs.
|
|
809
|
-
mapping:
|
|
836
|
+
mapping: "0",
|
|
810
837
|
change: "major",
|
|
811
|
-
hangHydration: 0,
|
|
812
|
-
haltHydration:
|
|
838
|
+
hangHydration: "0",
|
|
839
|
+
haltHydration: "0",
|
|
813
840
|
defaultApplicationHost: "kireji.app",
|
|
814
|
-
port: 3000
|
|
841
|
+
port: "3000"
|
|
815
842
|
})
|
package/src/build.js_.js
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
const boilerplate = ƒ.toString()
|
|
2
|
-
|
|
3
2
|
const sourceFile = new SourceMappedFile("../", undefined, "build.js")
|
|
4
3
|
sourceFile.addSection(boilerplate, sourceFile.addSource("build.js", boilerplate))
|
|
5
|
-
sourceFile.addSection(`\nƒ(${
|
|
6
|
-
if (typeof v === "bigint")
|
|
7
|
-
return v.toString() + "n"
|
|
8
|
-
|
|
9
|
-
return v
|
|
10
|
-
|
|
11
|
-
}, 1)})`, sourceFile.addSource(property.filename, property.content))
|
|
4
|
+
sourceFile.addSection(`\nƒ(${serialize(_)}, ${serialize(compressedSubjectOrigins)})`, sourceFile.addSource(property.filename, property.content))
|
|
12
5
|
const script = sourceFile.packAndMap()
|
|
13
6
|
return script
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
+
if (!scroller.query)
|
|
2
|
+
throw new ReferenceError(`Scrollers must define a css-style "query" property which can select the parent element of the scroller (from ${scroller.host}).`)
|
|
3
|
+
|
|
1
4
|
scroller.container = Q(scroller.query + ">scroller-")
|
|
5
|
+
|
|
6
|
+
if (!scroller.container)
|
|
7
|
+
throw new ReferenceError(`Could not find scroller parent element via query "${scroller.query}" (from ${scroller.host}).`)
|
|
8
|
+
|
|
2
9
|
scroller.scrollBar = Q(scroller.query + ">scroll-bar")
|
|
10
|
+
|
|
11
|
+
if (!scroller.scrollBar)
|
|
12
|
+
throw new ReferenceError(`Could not find scroller components in the element "${scroller.query}" (from ${scroller.host}). Use scroller.wrap to wrap the HTML contents of the element with the scroller's container and include the custom scroll bar HTML (from ${scroller.host}).`)
|
|
13
|
+
|
|
3
14
|
scroller.thumb = scroller.scrollBar.querySelector("thumb-")
|
|
4
15
|
scroller.content = Q(scroller.query + ">scroller->scroll-content")
|
|
5
16
|
scroller.container.scrollTop = scroller.fraction * scroller.container.scrollHeight
|
|
@@ -15,6 +15,8 @@ for (const code of hotKeys.pressed)
|
|
|
15
15
|
terminalKeys.add(code.slice(5).toLowerCase())
|
|
16
16
|
else if (/^(Minus|Equal|Semicolon|Quote|Comma|Period|Slash|Backquote|Backslash|Bracket(Right|Left)|Arrow(Up|Down|Left|Right)|Escape|Tab|Enter|Backspace)$/.test(code))
|
|
17
17
|
terminalKeys.add(code.toLowerCase())
|
|
18
|
+
else if (!production && code === "F8")
|
|
19
|
+
debugger
|
|
18
20
|
else debug("Unhandled Key Code: " + code)
|
|
19
21
|
|
|
20
22
|
const combo = [...terminalKeys].sort()
|
|
@@ -199,7 +199,7 @@ const httpServer = require('http').createServer((request, response) => logServer
|
|
|
199
199
|
/** @type {IVersionedExports} */
|
|
200
200
|
let destinationExports
|
|
201
201
|
try {
|
|
202
|
-
destinationExports = destinationVersion === _.version ? currentExports : require(
|
|
202
|
+
destinationExports = destinationVersion === _.version ? currentExports : require(`../../../.versions/${destinationVersion}.js`)
|
|
203
203
|
} catch {
|
|
204
204
|
throw `Bad Version: ${destinationVersion}`
|
|
205
205
|
}
|
|
@@ -211,7 +211,7 @@ const httpServer = require('http').createServer((request, response) => logServer
|
|
|
211
211
|
/** @type {IVersionedExports} */
|
|
212
212
|
let sourceExports
|
|
213
213
|
try {
|
|
214
|
-
sourceExports = require(
|
|
214
|
+
sourceExports = require(`../../../.versions/${sourceVersion}.js`)
|
|
215
215
|
} catch {
|
|
216
216
|
throw `Bad Version: ${sourceVersion}`
|
|
217
217
|
}
|
|
@@ -260,4 +260,4 @@ const httpServer = require('http').createServer((request, response) => logServer
|
|
|
260
260
|
}
|
|
261
261
|
))
|
|
262
262
|
|
|
263
|
-
httpServer.listen(_.port, () => logScope(0, `Server Ready - http://localhost:${_.port}`))
|
|
263
|
+
httpServer.listen(+_.port, () => logScope(0, `Server Ready - http://localhost:${_.port}`))
|
|
@@ -57,13 +57,13 @@ task-bar button,
|
|
|
57
57
|
task-bar menu-button {
|
|
58
58
|
height: var(--icon-size);
|
|
59
59
|
line-height: var(--icon-size);
|
|
60
|
-
cursor: pointer;
|
|
61
60
|
font-size: calc(var(--icon-size) * 1.2);
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
button:hover,
|
|
65
64
|
menu-button:hover {
|
|
66
65
|
color: var(--accent);
|
|
66
|
+
cursor: pointer;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
menu-button>img {
|
|
@@ -70,7 +70,7 @@ pointer.handle({
|
|
|
70
70
|
desktopIcons.setRouteID(0n)
|
|
71
71
|
|
|
72
72
|
const application = desktopIcons.superset[Number(TARGET_ELEMENT.getAttribute("data-index"))]
|
|
73
|
-
const targetLocation = (_.local ? `http://${application.host}.localhost:${_.port}` : `https://${application.host}`) + encodePathname(_.routeID)
|
|
73
|
+
const targetLocation = (+_.local ? `http://${application.host}.localhost:${_.port}` : `https://${application.host}`) + encodePathname(_.routeID)
|
|
74
74
|
location = targetLocation
|
|
75
75
|
},
|
|
76
76
|
getIntersectionMask() {
|
package/src/point.js
CHANGED
|
@@ -10,7 +10,7 @@ pointer.handle({
|
|
|
10
10
|
if (host !== _.application.host) {
|
|
11
11
|
if (host in _.applications) {
|
|
12
12
|
if (pathname === "/" && !hash) {
|
|
13
|
-
const targetLocation = (_.local ? `http://${host}.localhost:${_.port}` : `https://${host}`) + encodePathname(_.routeID)
|
|
13
|
+
const targetLocation = (+_.local ? `http://${host}.localhost:${_.port}` : `https://${host}`) + encodePathname(_.routeID)
|
|
14
14
|
location = targetLocation
|
|
15
15
|
} else warn(`Cross-host navigation and canonical pathname are not yet handled because of ambiguity between simply changing applications and linking to a canonical home page (while attempting to navigate to "${TARGET_ELEMENT.href}").`)
|
|
16
16
|
} else window.open(TARGET_ELEMENT.href, '_blank')
|
package/src/type.d.ts
CHANGED
|
@@ -289,7 +289,17 @@ declare function randomBits(bigCount: number): bigint
|
|
|
289
289
|
declare function randomRouteID(cardinality: bigint): bigint
|
|
290
290
|
/** Returns a random boolean value. */
|
|
291
291
|
declare function flipCoin(): boolean
|
|
292
|
-
/** The immutable list of runtime instances for the root space, in order of when
|
|
292
|
+
/** The immutable list of runtime instances for the root space, in order of when the were reached during recursive part hydration. */
|
|
293
293
|
declare const instances: IPartAny[]
|
|
294
|
-
/** The immutable list of every part in the root space, in order of when
|
|
295
|
-
declare const allParts: IPartAny[]
|
|
294
|
+
/** The immutable list of every part in the root space, in order of when the were reached during recursive part hydration. */
|
|
295
|
+
declare const allParts: IPartAny[]
|
|
296
|
+
/** The immutable list of every part host and filename combination, in order of when the were reached during recursive part hydration. */
|
|
297
|
+
declare const allSubjects: [host: string, filename?: string]
|
|
298
|
+
/** The Unix timestamp (in ms) when the current instance of the framework started booting. */
|
|
299
|
+
declare const bootStartTime: number
|
|
300
|
+
/** A map that provides information about whether a subject was defined in the project repository (maps to true) or only in the kireji framework package (maps to false). */
|
|
301
|
+
declare const subjectOrigins: Map<string, boolean>
|
|
302
|
+
/** A map that provides the index (in the `allSubjects` array) for the given subject. */
|
|
303
|
+
declare const subjectIndices: Map<string, boolean>
|
|
304
|
+
/** A base64-encoded string which represents a portable bitmask that compresses `subjectOrigins` in hydration order (because that order is identical between environments). */
|
|
305
|
+
declare const compressedSubjectOrigins: string
|