kireji 0.1.1 → 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/early-part.png +0 -0
- 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/part.png +0 -0
- package/src/app/kireji/static.css +2 -2
- package/src/build.js +115 -89
- 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 -4
- 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
|
Binary file
|
|
@@ -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
|
}
|
package/src/app/kireji/part.png
CHANGED
|
Binary file
|
|
@@ -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,15 +233,45 @@ 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) {
|
|
235
|
-
|
|
244
|
+
subjectOrigins.set("", true)
|
|
245
|
+
|
|
246
|
+
const
|
|
247
|
+
stats = { fileCount: 0, partCount: 0, ignoreCount: 0 },
|
|
248
|
+
{ readdirSync: readFolder, readFileSync: readFile, existsSync: exists } = require("fs"),
|
|
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
|
+
})
|
|
271
|
+
|
|
236
272
|
logScope(1, "Archiving Repository", archiveLog => {
|
|
237
|
-
warn("Warning: Not yet merging with framework source files.")
|
|
238
273
|
let lastLogFlush = Date.now()
|
|
239
274
|
const
|
|
240
|
-
{ readdirSync: readFolder, readFileSync: readFile, existsSync: exists } = require("fs"),
|
|
241
|
-
{ resolve } = require("path"),
|
|
242
275
|
batchedLogs = [],
|
|
243
276
|
bufferLog = (verbosity, msg) => {
|
|
244
277
|
if (verbosity > _.verbosity)
|
|
@@ -251,94 +284,69 @@ function ƒ(_) {
|
|
|
251
284
|
lastLogFlush = now
|
|
252
285
|
}
|
|
253
286
|
},
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
287
|
+
frameworkRoot = __dirname,
|
|
288
|
+
projectRoot = resolve(__dirname, "../../../src"),
|
|
289
|
+
readRecursive = domains => {
|
|
257
290
|
|
|
258
|
-
|
|
259
|
-
const baseEntries = exists(baseDir) ? readFolder(baseDir, { withFileTypes: true }) : []
|
|
260
|
-
const overlayEntries = exists(overlayDir) ? readFolder(overlayDir, { withFileTypes: true }) : []
|
|
291
|
+
const host = [...domains].reverse().join(".")
|
|
261
292
|
|
|
262
|
-
|
|
263
|
-
|
|
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}).`)
|
|
264
295
|
|
|
265
|
-
|
|
266
|
-
for (const entry of baseEntries)
|
|
267
|
-
unifiedEntries.set(entry.name, { entry, source: 'base' })
|
|
296
|
+
const mergedSubjects = new Map()
|
|
268
297
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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 })
|
|
272
302
|
|
|
273
|
-
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 })
|
|
274
307
|
|
|
275
|
-
|
|
276
|
-
debug(itemName)
|
|
277
|
-
// Ignore logic (TS files, hidden files, etc)
|
|
278
|
-
if (itemName.startsWith(".") || itemName === "Icon" || (!host && itemName === "build.js") || itemName.endsWith(".ts")) {
|
|
279
|
-
bufferLog(4, "".padEnd(depth, " ") + `⬚ ${itemName.padEnd(20, " ")} - ignored`)
|
|
280
|
-
continue
|
|
281
|
-
}
|
|
308
|
+
const part = domains.length ? {} : _
|
|
282
309
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
)
|
|
301
|
-
|
|
302
|
-
} else if (entry.isFile()) {
|
|
303
|
-
// Prioritize overlay file path, fallback to base
|
|
304
|
-
const actualPath = (source === 'overlay') ? nextOverlay : nextBase
|
|
305
|
-
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)`)
|
|
306
328
|
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// File processing (remains largely the same, but uses the prioritized path)
|
|
310
|
-
for (const [filename, filePath] of filenames) {
|
|
311
|
-
const isBinary = filename.endsWith("png") || filename.endsWith("gif")
|
|
312
|
-
const content = readFile(filePath, isBinary ? "base64" : "utf-8")
|
|
313
329
|
|
|
314
|
-
|
|
315
|
-
stats.fileCount++
|
|
316
|
-
bufferLog(3, "".padEnd(depth, " ") + `${isBinary ? "▣" : "≡"} ${filename}`)
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
stats.domainCount++
|
|
330
|
+
return part
|
|
320
331
|
}
|
|
321
332
|
|
|
322
|
-
readRecursive(
|
|
323
|
-
|
|
324
|
-
// TODO: Evaluate the timing of this action.
|
|
325
|
-
const configPath = resolve(__dirname, "../../../src/kireji.json")
|
|
326
|
-
if (exists(configPath))
|
|
327
|
-
Object.assign(_, require(configPath))
|
|
333
|
+
readRecursive([])
|
|
328
334
|
|
|
329
335
|
if (batchedLogs.length)
|
|
330
336
|
archiveLog(batchedLogs.join("\n") + "\n")
|
|
331
337
|
|
|
332
|
-
archiveLog(`Archived in ${Date.now() -
|
|
338
|
+
archiveLog(`Archived in ${Date.now() - bootStartTime}ms`)
|
|
333
339
|
})
|
|
334
340
|
|
|
335
|
-
logScope(2, "\
|
|
341
|
+
logScope(2, "\nDomain Stats", () => {
|
|
336
342
|
logAny(2, [{
|
|
337
|
-
Parts: { Amount: stats.
|
|
343
|
+
Parts: { Amount: stats.partCount },
|
|
338
344
|
Files: { Amount: stats.fileCount },
|
|
345
|
+
Ignored: { Amount: stats.ignoreCount }
|
|
339
346
|
}], "table")
|
|
340
347
|
})
|
|
341
348
|
}
|
|
349
|
+
|
|
342
350
|
logScope(1, "\nRecursively Hydrating Parts", hydrateLog => {
|
|
343
351
|
|
|
344
352
|
class SourceMappedFile {
|
|
@@ -405,7 +413,7 @@ function ƒ(_) {
|
|
|
405
413
|
packAndMap(url) {
|
|
406
414
|
const sourceFile = this
|
|
407
415
|
const script = sourceFile.lines.join("\n")
|
|
408
|
-
return _.mapping
|
|
416
|
+
return +_.mapping
|
|
409
417
|
? script +
|
|
410
418
|
`
|
|
411
419
|
//${"#"} sourceMappingURL=data:application/json;charset=utf-8;base64,${btoaUnicode(sourceFile.getMap())}${url
|
|
@@ -475,7 +483,7 @@ function ƒ(_) {
|
|
|
475
483
|
earlyImageSources = [],
|
|
476
484
|
partsByHost = {},
|
|
477
485
|
preHydrationArchive = serialize(_),
|
|
478
|
-
|
|
486
|
+
hydratePartsRecursive = (part, domains = []) => {
|
|
479
487
|
|
|
480
488
|
let host
|
|
481
489
|
|
|
@@ -517,7 +525,9 @@ function ƒ(_) {
|
|
|
517
525
|
const extendsString = part.manifest.extends ?? "part"
|
|
518
526
|
const relativeStepsBack = extendsString.match(/\.*$/)[0].length
|
|
519
527
|
const typename = relativeStepsBack ? `${extendsString.slice(0, -relativeStepsBack)}.${domains.slice(relativeStepsBack - 1).join(".")}` : extendsString.includes(".") ? extendsString : `${extendsString}.abstract.parts`
|
|
520
|
-
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}).`)
|
|
521
531
|
Object.setPrototypeOf(part, prototype)
|
|
522
532
|
part.define({
|
|
523
533
|
isAbstract: { value: part.manifest.abstract }
|
|
@@ -663,6 +673,8 @@ function ƒ(_) {
|
|
|
663
673
|
earlyImageSources.push([part, fn.slice(6)])
|
|
664
674
|
imageSources.push([part, fn])
|
|
665
675
|
}
|
|
676
|
+
subjectIndices.set(`${host}/${fn}`, allSubjects.length)
|
|
677
|
+
allSubjects.push([host, fn])
|
|
666
678
|
}
|
|
667
679
|
for (const methodID in part.manifest)
|
|
668
680
|
if (!["extends", "abstract"].includes(methodID))
|
|
@@ -691,7 +703,7 @@ function ƒ(_) {
|
|
|
691
703
|
part.define({ [identifier]: { value: childPart } })
|
|
692
704
|
}
|
|
693
705
|
|
|
694
|
-
|
|
706
|
+
hydratePartsRecursive(childPart, [subdomain, ...domains])
|
|
695
707
|
|
|
696
708
|
childPart.define({ "..": { value: part } })
|
|
697
709
|
|
|
@@ -700,10 +712,23 @@ function ƒ(_) {
|
|
|
700
712
|
}
|
|
701
713
|
if (!part.isAbstract) instances.push(part)
|
|
702
714
|
allParts.push(part)
|
|
715
|
+
subjectIndices.set(host, allSubjects.length)
|
|
716
|
+
allSubjects.push([host])
|
|
703
717
|
})
|
|
704
718
|
|
|
705
719
|
return part
|
|
706
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
|
+
},
|
|
707
732
|
countAndSortInheritorsRecursive = part => {
|
|
708
733
|
if (part.totalInheritors !== undefined)
|
|
709
734
|
return part.totalInheritors
|
|
@@ -718,7 +743,8 @@ function ƒ(_) {
|
|
|
718
743
|
return totalInheritors
|
|
719
744
|
}
|
|
720
745
|
|
|
721
|
-
|
|
746
|
+
hydratePartsRecursive(_)
|
|
747
|
+
hydrateSubjectOrigins()
|
|
722
748
|
countAndSortInheritorsRecursive(_.parts.abstract.part)
|
|
723
749
|
hydrateLog(`\nParts hydrated in ${Date.now() - hydrationStartTime}ms.`)
|
|
724
750
|
|
|
@@ -753,10 +779,10 @@ function ƒ(_) {
|
|
|
753
779
|
})
|
|
754
780
|
|
|
755
781
|
logScope(1, "\nBuilding Part Instances", buildLog => {
|
|
756
|
-
const
|
|
782
|
+
const bootStartTime = Date.now()
|
|
757
783
|
for (const part of instances)
|
|
758
784
|
part.startBuild()
|
|
759
|
-
buildLog(`Parts built in ${Date.now() -
|
|
785
|
+
buildLog(`Parts built in ${Date.now() - bootStartTime}ms.`)
|
|
760
786
|
})
|
|
761
787
|
|
|
762
788
|
logScope(2, "\nLogging Part Entropy", () => {
|
|
@@ -796,7 +822,7 @@ function ƒ(_) {
|
|
|
796
822
|
|
|
797
823
|
bootLog(`
|
|
798
824
|
╭┈┈┈┈┈┈┈┈┈┈┈ BOOT SUCCEEDED ┈┈┈┈┈┈┈┈┈┈┈╮
|
|
799
|
-
┊ Booted in ${(Date.now() -
|
|
825
|
+
┊ Booted in ${(Date.now() - bootStartTime + "ms.").padEnd(27, " ")}┊
|
|
800
826
|
┊ ┊
|
|
801
827
|
┊ End of synchronous script execution. ┊
|
|
802
828
|
╰┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╯
|
|
@@ -805,12 +831,12 @@ function ƒ(_) {
|
|
|
805
831
|
}
|
|
806
832
|
|
|
807
833
|
ƒ({
|
|
808
|
-
verbosity: 1,
|
|
834
|
+
verbosity: "1",
|
|
809
835
|
// TODO: Fix source mapping bugs.
|
|
810
|
-
mapping:
|
|
836
|
+
mapping: "0",
|
|
811
837
|
change: "major",
|
|
812
|
-
hangHydration: 0,
|
|
813
|
-
haltHydration:
|
|
838
|
+
hangHydration: "0",
|
|
839
|
+
haltHydration: "0",
|
|
814
840
|
defaultApplicationHost: "kireji.app",
|
|
815
|
-
port: 3000
|
|
841
|
+
port: "3000"
|
|
816
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()
|
|
@@ -100,7 +100,6 @@ logScope(1, `\nCreating Deployment Artifact`, log => {
|
|
|
100
100
|
if (!existsSync(archiveFolder))
|
|
101
101
|
mkdirSync(archiveFolder)
|
|
102
102
|
|
|
103
|
-
debug()
|
|
104
103
|
writeFileSync(artifactPath, _["build.js"])
|
|
105
104
|
|
|
106
105
|
log("Success.")
|
|
@@ -200,7 +199,7 @@ const httpServer = require('http').createServer((request, response) => logServer
|
|
|
200
199
|
/** @type {IVersionedExports} */
|
|
201
200
|
let destinationExports
|
|
202
201
|
try {
|
|
203
|
-
destinationExports = destinationVersion === _.version ? currentExports : require(
|
|
202
|
+
destinationExports = destinationVersion === _.version ? currentExports : require(`../../../.versions/${destinationVersion}.js`)
|
|
204
203
|
} catch {
|
|
205
204
|
throw `Bad Version: ${destinationVersion}`
|
|
206
205
|
}
|
|
@@ -212,7 +211,7 @@ const httpServer = require('http').createServer((request, response) => logServer
|
|
|
212
211
|
/** @type {IVersionedExports} */
|
|
213
212
|
let sourceExports
|
|
214
213
|
try {
|
|
215
|
-
sourceExports = require(
|
|
214
|
+
sourceExports = require(`../../../.versions/${sourceVersion}.js`)
|
|
216
215
|
} catch {
|
|
217
216
|
throw `Bad Version: ${sourceVersion}`
|
|
218
217
|
}
|
|
@@ -261,4 +260,4 @@ const httpServer = require('http').createServer((request, response) => logServer
|
|
|
261
260
|
}
|
|
262
261
|
))
|
|
263
262
|
|
|
264
|
-
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
|