gitoriaLog in with ident

gitoria

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Commitcc7bf7bacc7bf7bamission 002 (code order) 3/4: let only where a variable is reassigned or re-bound in a loop body (289 lets → plain declarations; 213 left: 125 reassigned, 88 loop-bound; no member/import/param clash). gates 200/0, 46/0, 44/0; real-data reads + writes identical (browser modules: var → const only)mrecc7bf7ba/lib/git-helpers.hl

4.5 KB

  1. // lib/git-helpers.hl — what the git readers look up: path and name checks, ids, tab-separated fields, sizes, and the
  2. // commit-subject markers of pull requests (`|||PR`) and releases (`|||RL`). Statics only, git itself is not called here.
  3. // a path we let through: printable, no leading dash, no backslash / quote / control characters
  4. static safePath = (path) => {
  5. if (path == null || path == '' || path.length > 300 || path.startsWith('-')) { return false }
  6. let i = 0
  7. while (i < path.length) {
  8. let c = path.charCodeAt(i)
  9. if (c < 32 || c == 127 || c == 34 || c == 92 || c == 58) { return false }
  10. i = i + 1
  11. }
  12. return true
  13. }
  14. static safeName = (n) => { return safePath(n) && n.length <= 100 && !n.endsWith('/') && !n.includes('//') }
  15. // a URL path piece: percent-encoded, the slashes kept (encodeURIComponent is a global since hybriel #14)
  16. static enc = (s) => { return encodeURIComponent(s).replaceAll('%2F', '/') }
  17. static isHexId = (s) => {
  18. if (s == null || s.length < 4 || s.length > 40) { return false }
  19. let i = 0
  20. while (i < s.length) {
  21. let c = s.charCodeAt(i)
  22. if (!((c >= 48 && c <= 57) || (c >= 97 && c <= 102))) { return false }
  23. i = i + 1
  24. }
  25. return true
  26. }
  27. // tab-separated fields of a line git wrote. (split() / indexOf() do not find a tab in a line that
  28. // came from hl:proc, so scan by character code.)
  29. static tabAt = (line) => {
  30. let i = 0
  31. while (i < line.length) {
  32. if (line.charCodeAt(i) == 9) { return i }
  33. i = i + 1
  34. }
  35. return -1
  36. }
  37. static tabs = (line) => {
  38. out = []
  39. let start = 0
  40. let i = 0
  41. while (i < line.length) {
  42. if (line.charCodeAt(i) == 9) {
  43. out.push(line.slice(start, i))
  44. start = i + 1
  45. }
  46. i = i + 1
  47. }
  48. out.push(line.slice(start))
  49. return out
  50. }
  51. static sizeText = (n) => {
  52. if (n < 1024) { return n + ' B' }
  53. unit = n < 1048576 ? 1024 : 1048576
  54. t = (n * 10 - (n * 10) % unit) / unit
  55. return ((t - t % 10) / 10) + '.' + (t % 10) + (n < 1048576 ? ' KB' : ' MB')
  56. }
  57. // ---- the markers (pulls.hl, releases.hl) ----------------------------------------------------------
  58. // a commit subject → null (not a request) or { target: '' (= default) | name, title }
  59. static parsePull = (subject) => {
  60. if (subject == null) { return null }
  61. if (subject == '|||PR') { return { target = '' title = '' } }
  62. if (subject.startsWith('|||PR ')) { return { target = '' title = subject.slice(6).trim() } }
  63. if (subject.startsWith('|||PR|')) {
  64. close = subject.indexOf(']')
  65. if (close < 7) { return null }
  66. let target = subject.slice(6, close)
  67. rest = subject.slice(close + 1)
  68. if (rest != '' && !rest.startsWith(' ')) { return null }
  69. if (!safeName(target)) { return null }
  70. return { target = target title = rest.trim() }
  71. }
  72. return null
  73. }
  74. static isDigits = (s) => {
  75. if (s == '' || s.length > 9) { return false }
  76. let i = 0
  77. while (i < s.length) {
  78. let c = s.charCodeAt(i)
  79. if (c < 48 || c > 57) { return false }
  80. i = i + 1
  81. }
  82. return true
  83. }
  84. // the part of a version after its patch digits: only letters, digits, `.` and `-`
  85. static suffixOk = (s) => {
  86. let i = 0
  87. while (i < s.length) {
  88. let c = s.charCodeAt(i)
  89. if (!((c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || c == 45 || c == 46)) { return false }
  90. i = i + 1
  91. }
  92. return true
  93. }
  94. // `1.2.3` or `1.2.3a` → { major, minor, patch, text } or null
  95. static parseVersion = (t) => {
  96. if (t == null || t.length > 32) { return null }
  97. parts = t.split('.')
  98. if (parts.length < 3) { return null }
  99. if (!isDigits(parts[0]) || !isDigits(parts[1])) { return null }
  100. rest = parts.slice(2).join('.')
  101. let n = 0
  102. while (n < rest.length && rest.charCodeAt(n) >= 48 && rest.charCodeAt(n) <= 57) { n = n + 1 }
  103. if (n == 0 || n > 9 || !suffixOk(rest.slice(n))) { return null }
  104. return { major = toNumber(parts[0]) minor = toNumber(parts[1]) patch = toNumber(rest.slice(0, n)) text = t }
  105. }
  106. // a commit subject → null (not a release) or { kind: 'patch' | 'med' | 'mj' | 'set', version, title }
  107. static parseRelease = (subject) => {
  108. if (subject == null) { return null }
  109. if (subject == '|||RL') { return { kind = 'patch' version = null title = '' } }
  110. if (subject.startsWith('|||RL ')) { return { kind = 'patch' version = null title = subject.slice(6).trim() } }
  111. if (subject.startsWith('|||RL|')) {
  112. body = subject.slice(6)
  113. sp = body.indexOf(' ')
  114. token = sp < 0 ? body : body.slice(0, sp)
  115. let title = sp < 0 ? '' : body.slice(sp + 1).trim()
  116. if (token == 'med') { return { kind = 'med' version = null title = title } }
  117. if (token == 'mj') { return { kind = 'mj' version = null title = title } }
  118. v = parseVersion(token)
  119. if (v == null) { return null }
  120. return { kind = 'set' version = v title = title }
  121. }
  122. return null
  123. }

Branches

Latest commits

  • cc7bf7bamission 002 (code order) 3/4: let only where a variable is reassigned or re-bound in a loop body (289 lets → plain declarations; 213 left: 125 reassigned, 88 loop-bound; no member/import/param clash). gates 200/0, 46/0, 44/0; real-data reads + writes identical (browser modules: var → const only)mre
  • 090a20c6mission 002 (code order) 2/4: one lib/ file per topic — git.hl split into git (calls, branches, init, temp folder) / homepage / code / pulls / releases (+ git-helpers: paths, ids, |||PR/|||RL markers); repos-helpers, tickets-helpers, transport-helpers; util.hl = localtime + env, storage dir, addresses, lists, text checks, one newest-first sort (was 3 copies); the function routes out of project.hl into lib/api.hl (thin; plumbing in api-helpers.hl), sshgate.hl folded into api.hl + sshkeys.hl keyLine + repos.hl mayPush; 'Make main' and the merge answer out of the faces (code.hl makeMain, pulls.hl pullsView), one login helper (users.hl userOfLoginCode); project.hl is the map. Session-writing routes get &req + &server.sessions. gates 200/0, 46/0, 44/0; real-data identical except /login/failed now shows the parked reason for a browser that already had a session (the old copy-of-req lost it)mre
  • 110c2799mission 002 (code order) 1/4: .hl files out of the root — lib/ (api, git, localtime, markdown, repos, sshgate, sshkeys, tickets, tokens, transport, users), components/styles.hl; jsoncheck.hl removed (imported nowhere); import paths only. gates 200/0, 46/0, 44/0; real-data reads + writes identicalmre
  • fdfb4b1bgitoria: Hybriel master 06617221 (plugin allocators 3a781359 + 413f60e4, mpackdb 2cb7ae5e, http1 773de63e); gates 200/0, 46/0, 44/0mre
  • 5b46ac84antcolony#40: LOG.md — missions 069/072 are antcolony missions (report paths on Byrodin)mre
  • 5602ff41gitoria: Hybriel master 190aa11d (fc838894 GC correctness, #127 mountKids by reference, #126, #48) — tracker README flat; gates 200/0, 46/0, 44/0mre
  • e85eaf01gitoria: 069 round 2 — hybriel 1a096ad3 not adopted (Markdown SSR still grows); browser gate waits for the server-side logout before restartmre
  • 09ce4f3fgitoria: mission 069 re-vendor hybriel 8efba065 stopped (big SSR pages grow + slow down); lambda audit clean; old vendor keptmre
  • 3dc43108antcolony#40: mission references point to the moved missionsmre
  • 8d9450fdantcolony#40: history (LOG.md), worker briefs (missions/) and reports moved here from antcolony, numbered per project; old numbers in antcolony docs/mission-map.mdmre
  • 205d5fe4gitoria: Hybriel master ff51cf46; ssh keys/tokens no double rows (session sync); gates follow #20mre
  • 9b27cb26gitoria#21: installable app (manifest, service worker, offline start page), own iconmre
  • 68dcb603deploy.sh: back up live storage/.sessions/.env before every deploy (newest 5 kept)mre
  • e2deed6dgitoria#20: "Add code" only on the Code page of an empty repository, no collapsiblemre
  • 8bb97ffddeploy.sh: never send .git or .gitignore to Byrodinmre
  • fd981932State of 2026-09-27; bin/ no longer tracked (Hybriel commit is in README)mre
  • 4a2d7125initial commitmre