vanilla deepsearch

This commit is contained in:
Asaki Yuki 2026-01-18 01:59:02 +07:00
parent a144909fbf
commit ac412b798c
15 changed files with 725 additions and 78 deletions

2
.gitignore vendored
View file

@ -1,4 +1,4 @@
dist dist
prefetch cache
node_modules node_modules
.tsbuildinfo .tsbuildinfo

View file

@ -24,7 +24,10 @@
"dev": "npx tsc --watch", "dev": "npx tsc --watch",
"test": "bun test/app.ts", "test": "bun test/app.ts",
"test:watch": "bun --watch test/app.ts", "test:watch": "bun --watch test/app.ts",
"prefetch": "bun scripts/prefetch" "prefetch": "bun scripts/prefetch",
"gen:enums": "bun scripts/write/enum",
"vanilla:defs": "bun scripts/vanilladefs",
"vanilla:autocomplete": "bun scripts/autocomplete-build"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^25.0.3", "@types/node": "^25.0.3",

View file

@ -0,0 +1,37 @@
import fs from "fs"
const data: any = JSON.parse(fs.readFileSync("cache/vanilla-defs.json", "utf-8"))
function toCamelCase(str: string) {
return str.replace(/[-_]\w/g, m => m[1].toUpperCase())
}
const type: string[] = []
const $$namespace: string[] = []
const intelliSense: string[] = ['import * as mc from "./elements.js"\n', "export type IntelliSense = {"]
for (const [namespace, element] of Object.entries(data)) {
if (namespace === "undefined") continue
$$namespace.push(`"${namespace}"`)
const $namespace = toCamelCase("_" + namespace)
const eType: string[] = []
for (const [ePath, info] of Object.entries(<any>element)) {
const { file, type, extend } = <any>info
eType.push(`"${ePath}"`)
}
intelliSense.push(` "${namespace}": mc.${$namespace},`)
type.push(`export type ${$namespace} = ${eType.join(" | ")};`)
}
intelliSense.push("}")
fs.writeFileSync(
"src/types/vanilla/elements.ts",
`export type Namespace = ${$$namespace.join(" | ")}\n\n` + type.join("\n"),
)
fs.writeFileSync("src/types/vanilla/intellisense.ts", intelliSense.join("\n"))

View file

@ -2,13 +2,13 @@ import JSONC from "jsonc-parser"
import fsp from "fs/promises" import fsp from "fs/promises"
import fs from "fs" import fs from "fs"
if (!fs.existsSync("prefetch")) fs.mkdirSync("prefetch") if (!fs.existsSync("cache")) fs.mkdirSync("cache")
export const Github = { export const Github = {
readFile: async (user: string, repo: string, branches: string, path: string) => { readFile: async (user: string, repo: string, branches: string, path: string) => {
try { try {
return fetch(`https://raw.githubusercontent.com/${user}/${repo}/refs/heads/${branches}/${path}`).then(res => return fetch(`https://raw.githubusercontent.com/${user}/${repo}/refs/heads/${branches}/${path}`).then(res =>
res.text() res.text(),
) )
} catch (error) { } catch (error) {
console.error(error) console.error(error)
@ -21,7 +21,7 @@ export const PFFS = {
// Sync // Sync
readFile: (file: string) => { readFile: (file: string) => {
try { try {
return fs.readFileSync(`prefetch/${file}`, "utf-8") return fs.readFileSync(`cache/${file}`, "utf-8")
} catch (error) { } catch (error) {
console.error(error) console.error(error)
process.exit(1) process.exit(1)
@ -31,11 +31,11 @@ export const PFFS = {
writeFile: (file: string, data: string) => { writeFile: (file: string, data: string) => {
try { try {
file.split("/").reduce((a, b) => { file.split("/").reduce((a, b) => {
if (!fs.existsSync(a)) fs.mkdirSync(a) if (!fs.existsSync("cache/" + a)) fs.mkdirSync("cache/" + a)
return `prefetch/${a}/${b}` return `${a}/${b}`
}) })
return fsp.writeFile(`prefetch/${file}`, data) return fsp.writeFile(`cache/${file}`, data)
} catch (error) { } catch (error) {
console.error(error) console.error(error)
process.exit(1) process.exit(1)

View file

@ -1,5 +1,32 @@
import { Github, PFFS } from "./components" import { Github, PFFS } from "./components"
import { parse } from "jsonc-parser"
Github.readFile("KalmeMarq", "Bugrock-JSON-UI-Schemas", "main", "ui.schema.json").then(data => { const user = "mojang"
PFFS.writeFile("ui.schema.json", data) const project = "bedrock-samples"
}) const branches = process.argv.includes("--preview") ? "preview" : "main"
async function fetchfile(path: string) {
return parse(await Github.readFile(user, project, branches, path))
}
async function main() {
console.log("Prefetching...")
const data = await Github.readFile("KalmeMarq", "Bugrock-JSON-UI-Schemas", "main", "ui.schema.json")
await PFFS.writeFile("ui.schema.json", data)
console.log("ui.schema.json fetched!")
const { ui_defs } = await fetchfile("resource_pack/ui/_ui_defs.json")
await PFFS.writeFile("ui_defs.json", JSON.stringify(ui_defs, null, 2))
console.log("ui_defs.json fetched!")
let fetched = 0
await Promise.all(
ui_defs.map(async (path: string) => {
const data = await fetchfile("resource_pack/" + path)
await PFFS.writeFile(path, JSON.stringify(data, null, 2))
console.log(`[${++fetched}/${ui_defs.length}] ${path}`)
}),
)
}
main()

158
scripts/vanilladefs.ts Normal file
View file

@ -0,0 +1,158 @@
import fs from "fs"
const files: string[] = JSON.parse(fs.readFileSync("cache/ui_defs.json", "utf-8"))
const vanilla: NamespaceMap = new Map()
function readControls(namespace: string, file: string, elements: ElementMap, data: any[], prefix: string) {
prefix += "/"
for (const element of data) {
const [fullname, properties] = Object.entries(element)[0]
const data: VanillaElement = {
file,
type: (<any>properties).type,
}
const [name, $2] = fullname.split("@")
if (name.startsWith("$")) continue
if ($2 && !$2.startsWith("$")) {
const [$3, $4] = $2.split(".")
if ($4) {
data.extend = {
name: $4,
namespace: $3,
}
} else {
data.extend = {
name: $3,
namespace,
}
}
}
elements.set(prefix + name, data)
const controls = (<any>properties).controls
if (controls) {
readControls(namespace, file, elements, controls, prefix + name)
}
}
}
function readData(namespace: string, file: string, elements: ElementMap, data: any) {
for (const [fullname, properties] of Object.entries(data)) {
const [name, $2] = fullname.split("@")
const data: VanillaElement = {
file,
type: (<any>properties).type,
}
if ((<any>properties).anim_type) {
data.anim_type = (<any>properties).anim_type
}
// Register element
if ($2) {
const [$3, $4] = $2.split(".")
if ($4) {
data.extend = {
name: $4,
namespace: $3,
}
} else {
data.extend = {
name: $3,
namespace,
}
}
}
elements.set(name, data)
const controls = (<any>properties).controls
if (controls) {
readControls(namespace, file, elements, controls, name)
}
}
}
// Read
for (const file of files) {
const { namespace, ...data } = JSON.parse(fs.readFileSync("cache/" + file, "utf-8"))
let elements = vanilla.get(namespace)
if (!elements) {
elements = new Map<Namespace, VanillaElement>()
vanilla.set(namespace, elements)
}
readData(namespace, file, elements, data)
}
// Format
function getActualType(name: string, namespace: string) {
const e = vanilla.get(namespace)?.get(name)!
if (e?.anim_type) return null
if (e?.type) {
return e.type
} else {
if (e?.extend) {
return getActualType(e.extend.name, e.extend.namespace)
}
}
}
for (const [namespace, elements] of vanilla) {
for (const [name, element] of elements) {
if (element.extend) {
const type = getActualType(element.extend.name, element.extend.namespace)
if (type) {
element.type = type
elements.set(name, element)
} else if (type === null) {
vanilla.get(namespace)?.delete(name)
}
}
}
}
for (const [namespace, elements] of vanilla) {
for (const [name, element] of elements) {
if (element.anim_type) {
vanilla.get(namespace)?.delete(name)
}
}
}
const json: any = {}
for (const [namespace, elements] of vanilla) {
json[namespace] ||= {}
for (const [name, element] of elements) {
element.type ||= "unknown"
json[namespace][name] = element
}
}
fs.writeFileSync("cache/vanilla-defs.json", JSON.stringify(json, null, 4))
// Types
interface VanillaElement {
extend?: {
name: string
namespace: string
}
anim_type?: string
type: string
file: string
}
type Name = string
type Namespace = string
type ElementMap = Map<Name, VanillaElement>
type NamespaceMap = Map<Namespace, ElementMap>

View file

@ -11,6 +11,7 @@ for (const key in schema) {
const data = schema[key] const data = schema[key]
if (data.enum) { if (data.enum) {
const enumName = key.match(/\w+$/)?.[0].toCamelCase(true)! const enumName = key.match(/\w+$/)?.[0].toCamelCase(true)!
console.log(enumName)
index.push(`export { ${enumName} } from "./${enumName}.js"`) index.push(`export { ${enumName} } from "./${enumName}.js"`)
const count = new Map<string, number>() const count = new Map<string, number>()

View file

@ -36,11 +36,7 @@ export class Parser {
let left = this.parseAndExpression(), let left = this.parseAndExpression(),
current current
while ( while ((current = this.at()) && this.at().kind === TokenKind.OPERATOR && current.value === "||") {
(current = this.at()) &&
this.at().kind === TokenKind.OPERATOR &&
["||"].includes(<string>current.value)
) {
this.eat() this.eat()
left = `(${left} or ${this.parseAndExpression()})` left = `(${left} or ${this.parseAndExpression()})`
} }
@ -52,11 +48,7 @@ export class Parser {
let left = this.parseComparisonExpression(), let left = this.parseComparisonExpression(),
current current
while ( while ((current = this.at()) && this.at().kind === TokenKind.OPERATOR && current.value === "&&") {
(current = this.at()) &&
this.at().kind === TokenKind.OPERATOR &&
["&&"].includes(<string>current.value)
) {
this.eat() this.eat()
left = `(${left} and ${this.parseComparisonExpression()})` left = `(${left} and ${this.parseComparisonExpression()})`
} }
@ -156,9 +148,8 @@ export class Parser {
case TokenKind.STRING: case TokenKind.STRING:
return <string>this.eat().value return <string>this.eat().value
case TokenKind.TEMPLATE_STRING: case TokenKind.TEMPLATE_STRING: {
return `(${(<TSToken[]>this.eat().value) const out = (<TSToken[]>this.eat().value).map(v => {
.map(v => {
if (v.kind === TSTokenKind.STRING) return v.tokens.value if (v.kind === TSTokenKind.STRING) return v.tokens.value
else { else {
const bakTokens = this.tokens const bakTokens = this.tokens
@ -175,7 +166,8 @@ export class Parser {
return out return out
} }
}) })
.join(" + ")})` return out.length === 1 ? (out[0] as string) : `(${out.join(" + ")})`
}
case TokenKind.OPERATOR: { case TokenKind.OPERATOR: {
if (left.value === "-" || left.value === "+") { if (left.value === "-" || left.value === "+") {
@ -216,11 +208,10 @@ export class Parser {
} }
default: default:
console.log(left)
this.expect(TokenKind.NUMBER, "Unexpected token!") this.expect(TokenKind.NUMBER, "Unexpected token!")
} }
return <string>left.value return left.value
} }
private parseCallableOrLiteral(callerToken: Token): Expression { private parseCallableOrLiteral(callerToken: Token): Expression {
@ -249,12 +240,15 @@ export class Parser {
this.eat() this.eat()
return this.funtionCall(<string>callerToken.value, ...args) return this.funtionCall(<string>callerToken.value, ...args)
} else { } else if (left.kind === TokenKind.OPERATOR) {
this.warn( this.warn(
`Implicit string literal '${callerToken.value}'. Use quoted string ('${callerToken.value}') for clarity!`, `Implicit string literal '${callerToken.value}'. Use quoted string ('${callerToken.value}') for clarity!`,
callerToken, callerToken,
) )
return <string>callerToken.value return <string>callerToken.value
} else {
this.expect(TokenKind.OPERATOR, "Unexpected token!")
return <string>callerToken.value
} }
} }

5
src/components/Modify.ts Normal file
View file

@ -0,0 +1,5 @@
import { Namespace } from "../types/vanilla/elements.js"
import { IntelliSense } from "../types/vanilla/intellisense.js"
import { UI } from "./UI.js"
export function Modify<T extends Namespace>(namespace: T, name: IntelliSense[T]) {}

View file

@ -3,6 +3,7 @@ import "./compilers/RunEnd.js"
export * from "./components/Animation.js" export * from "./components/Animation.js"
export * from "./components/UI.js" export * from "./components/UI.js"
export * from "./components/Modify.js"
export * from "./components/Utils.js" export * from "./components/Utils.js"
export * from "./types/enums/index.js" export * from "./types/enums/index.js"

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,2 @@
export * from "./elements.js"
export * from "./intellisense.js"

View file

@ -0,0 +1,212 @@
import * as mc from "./elements.js"
export type IntelliSense = {
achievement: mc.Achievement
add_external_server: mc.AddExternalServer
adhoc_inprogress: mc.AdhocInprogress
adhoc: mc.Adhoc
anvil: mc.Anvil
anvil_pocket: mc.AnvilPocket
authentication_modals: mc.AuthenticationModals
authentication: mc.Authentication
auto_save_info: mc.AutoSaveInfo
beacon: mc.Beacon
beacon_pocket: mc.BeaconPocket
blast_furnace: mc.BlastFurnace
book: mc.Book
brewing_stand: mc.BrewingStand
brewing_stand_pocket: mc.BrewingStandPocket
bundle_purchase_warning: mc.BundlePurchaseWarning
cartography: mc.Cartography
cartography_pocket: mc.CartographyPocket
chalkboard: mc.Chalkboard
chat: mc.Chat
chat_settings: mc.ChatSettings
chest: mc.Chest
choose_realm: mc.ChooseRealm
coin_purchase: mc.CoinPurchase
command_block: mc.CommandBlock
confirm_delete_account: mc.ConfirmDeleteAccount
content_log: mc.ContentLog
content_log_history: mc.ContentLogHistory
crafter_pocket: mc.CrafterPocket
create_world_upsell: mc.CreateWorldUpsell
credits: mc.Credits
csb_purchase_error: mc.CsbPurchaseError
csb: mc.Csb
csb_content: mc.CsbContent
csb_banner: mc.CsbBanner
csb_buy: mc.CsbBuy
common_csb: mc.CommonCsb
csb_purchase_amazondevicewarning: mc.CsbPurchaseAmazondevicewarning
csb_purchase_warning: mc.CsbPurchaseWarning
csb_subscription_panel: mc.CsbSubscriptionPanel
csb_upsell: mc.CsbUpsell
csb_packs: mc.CsbPacks
csb_welcome: mc.CsbWelcome
csb_faq: mc.CsbFaq
csb_landing: mc.CsbLanding
custom_templates: mc.CustomTemplates
world_conversion_complete: mc.WorldConversionComplete
day_one_experience_intro: mc.DayOneExperienceIntro
day_one_experience: mc.DayOneExperience
death: mc.Death
debug_screen: mc.DebugScreen
dev_console: mc.DevConsole
disconnect: mc.Disconnect
display_logged_error: mc.DisplayLoggedError
discovery_dialog: mc.DiscoveryDialog
edu_featured: mc.EduFeatured
edu_quit_button: mc.EduQuitButton
persona_emote: mc.PersonaEmote
enchanting: mc.Enchanting
enchanting_pocket: mc.EnchantingPocket
encyclopedia: mc.Encyclopedia
expanded_skin_pack: mc.ExpandedSkinPack
feed_common: mc.FeedCommon
file_upload: mc.FileUpload
furnace: mc.Furnace
furnace_pocket: mc.FurnacePocket
game_tip: mc.GameTip
gamepad_disconnected: mc.GamepadDisconnected
gameplay: mc.Gameplay
gathering_info: mc.GatheringInfo
globalpause: mc.Globalpause
grindstone: mc.Grindstone
grindstone_pocket: mc.GrindstonePocket
gamma_calibration: mc.GammaCalibration
horse: mc.Horse
horse_pocket: mc.HorsePocket
how_to_play_common: mc.HowToPlayCommon
how_to_play: mc.HowToPlay
hud: mc.Hud
host_options: mc.HostOptions
bed: mc.Bed
im_reader: mc.ImReader
crafting: mc.Crafting
crafting_pocket: mc.CraftingPocket
invite: mc.Invite
jigsaw_editor: mc.JigsawEditor
late_join: mc.LateJoin
library_modal: mc.LibraryModal
local_world_picker: mc.LocalWorldPicker
loom: mc.Loom
loom_pocket: mc.LoomPocket
manage_feed: mc.ManageFeed
manifest_validation: mc.ManifestValidation
sdl_label: mc.SdlLabel
sdl_dropdowns: mc.SdlDropdowns
sdl_image_row: mc.SdlImageRow
sdl_text_row: mc.SdlTextRow
mob_effect: mc.MobEffect
non_xbl_user_management: mc.NonXblUserManagement
npc_interact: mc.NpcInteract
online_safety: mc.OnlineSafety
pack_settings: mc.PackSettings
panorama: mc.Panorama
patch_notes: mc.PatchNotes
pause: mc.Pause
pdp: mc.Pdp
pdp_screenshots: mc.PdpScreenshots
permissions: mc.Permissions
persona_cast_character_screen: mc.PersonaCastCharacterScreen
persona_common: mc.PersonaCommon
persona_popups: mc.PersonaPopups
play: mc.Play
perf_turtle: mc.PerfTurtle
pocket_containers: mc.PocketContainers
popup_dialog: mc.PopupDialog
portfolio: mc.Portfolio
progress: mc.Progress
rating_prompt: mc.RatingPrompt
realms_common: mc.RealmsCommon
realms_create: mc.RealmsCreate
realms_pending_invitations: mc.RealmsPendingInvitations
realms_slots: mc.RealmsSlots
realms_settings: mc.RealmsSettings
realms_allowlist: mc.RealmsAllowlist
realms_invite_link_settings: mc.RealmsInviteLinkSettings
realms_plus_ended: mc.RealmsPlusEnded
realmsPlus: mc.RealmsPlus
realmsPlus_content: mc.RealmsPlusContent
realmsPlus_faq: mc.RealmsPlusFaq
realmsPlus_landing: mc.RealmsPlusLanding
realmsPlus_buy: mc.RealmsPlusBuy
realmsPlus_packs: mc.RealmsPlusPacks
realmsPlus_purchase_warning: mc.RealmsPlusPurchaseWarning
realms_stories_transition: mc.RealmsStoriesTransition
redstone: mc.Redstone
resource_packs: mc.ResourcePacks
safe_zone: mc.SafeZone
storage_migration_common: mc.StorageMigrationCommon
storage_migration_generic: mc.StorageMigrationGeneric
scoreboard: mc.Scoreboard
screenshot: mc.Screenshot
select_world: mc.SelectWorld
server_form: mc.ServerForm
settings: mc.Settings
controls_section: mc.ControlsSection
general_section: mc.GeneralSection
realms_world_section: mc.RealmsWorldSection
settings_common: mc.SettingsCommon
world_section: mc.WorldSection
social_section: mc.SocialSection
sidebar_navigation: mc.SidebarNavigation
sign: mc.Sign
simple_inprogress: mc.SimpleInprogress
skin_pack_purchase: mc.SkinPackPurchase
skin_picker: mc.SkinPicker
smithing_table: mc.SmithingTable
smithing_table_2: mc.SmithingTable2
smithing_table_pocket: mc.SmithingTablePocket
smithing_table_2_pocket: mc.SmithingTable2Pocket
smoker: mc.Smoker
start: mc.Start
stonecutter: mc.Stonecutter
stonecutter_pocket: mc.StonecutterPocket
storage_management: mc.StorageManagement
storage_management_popup: mc.StorageManagementPopup
common_store: mc.CommonStore
store_layout: mc.StoreLayout
filter_menu: mc.FilterMenu
store_inventory: mc.StoreInventory
store_item_list: mc.StoreItemList
store_progress: mc.StoreProgress
promo_timeline: mc.PromoTimeline
store_sale_item_list: mc.StoreSaleItemList
store_search: mc.StoreSearch
sort_menu: mc.SortMenu
structure_editor: mc.StructureEditor
submit_feedback: mc.SubmitFeedback
tabbed_upsell: mc.TabbedUpsell
thanks_for_testing: mc.ThanksForTesting
third_party_store: mc.ThirdPartyStore
toast_screen: mc.ToastScreen
token_faq: mc.TokenFaq
trade: mc.Trade
trade_pocket: mc.TradePocket
trade2: mc.Trade2
trade2_pocket: mc.Trade2Pocket
trialUpsell: mc.TrialUpsell
ugc_viewer: mc.UgcViewer
common_art: mc.CommonArt
common: mc.Common
"common-classic": mc.CommonClassic
edu_common: mc.EduCommon
purchase_common: mc.PurchaseCommon
common_buttons: mc.CommonButtons
common_dialogs: mc.CommonDialogs
common_tabs: mc.CommonTabs
common_toggles: mc.CommonToggles
friendsbutton: mc.Friendsbutton
iconbutton: mc.Iconbutton
update_dimensions: mc.UpdateDimensions
update_version: mc.UpdateVersion
world_recovery: mc.WorldRecovery
world_templates: mc.WorldTemplates
xbl_console_qr_signin: mc.XblConsoleQrSignin
xbl_console_signin: mc.XblConsoleSignin
xbl_console_signin_succeeded: mc.XblConsoleSigninSucceeded
xbl_immediate_signin: mc.XblImmediateSignin
win10_trial_conversion: mc.Win10TrialConversion
}

View file

@ -1,4 +1 @@
import { Lexer, Parser } from ".." import { Modify } from ".."
const { out } = new Parser("`A${`#a${#a + #b}`}A`").out()
console.log(out)