Skip to content

Commit

Permalink
🐛 Formatter fixes and export some stuff (#1639)
Browse files Browse the repository at this point in the history
  • Loading branch information
misode authored Nov 22, 2024
1 parent ee4fefa commit 65355b1
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 82 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/common/externals/BrowserExternals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import type {
} from './index.js'

type Listener = (...args: unknown[]) => unknown
class BrowserEventEmitter implements ExternalEventEmitter {
export class BrowserEventEmitter implements ExternalEventEmitter {
readonly #listeners = new Map<string, { all: Set<Listener>; once: Set<Listener> }>()

emit(eventName: string, ...args: unknown[]): boolean {
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/processor/formatter/builtin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {
BooleanBaseNode,
BooleanNode,
CommentNode,
ErrorNode,
FileNode,
FloatBaseNode,
FloatNode,
Expand All @@ -22,6 +23,10 @@ export const fallback: Formatter = (node) => {
throw new Error(`No formatter registered for type ${node.type}`)
}

export const error: Formatter<ErrorNode> = (node) => {
return ''
}

export const file: Formatter<FileNode<AstNode>> = (node, ctx) => {
return node.children.map((child) => {
return ctx.meta.getFormatter(child.type)(child, ctx)
Expand Down Expand Up @@ -62,6 +67,7 @@ export const string: Formatter<StringBaseNode> = (node) => {
}

export function registerFormatters(meta: MetaRegistry) {
meta.registerFormatter<ErrorNode>('error', error)
meta.registerFormatter<FileNode<AstNode>>('file', file)
meta.registerFormatter<BooleanNode>('boolean', boolean)
meta.registerFormatter<CommentNode>('comment', comment)
Expand Down
79 changes: 3 additions & 76 deletions packages/java-edition/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
symbolRegistrar,
} from './dependency/index.js'
import * as jeJson from './json/index.js'
import { registerMcdocAttributes, registerPackFormatAttribute } from './mcdocAttributes.js'
import * as jeMcf from './mcfunction/index.js'

export * as binder from './binder/index.js'
Expand Down Expand Up @@ -121,82 +122,8 @@ export const initialize: core.ProjectInitializer = async (ctx) => {
&& !n.symbol?.path[0]?.startsWith('::minecraft')),
})

mcdoc.runtime.registerAttribute(meta, 'since', mcdoc.runtime.attribute.validator.string, {
filterElement: (config, ctx) => {
if (!config.startsWith('1.')) {
ctx.logger.warn(`Invalid mcdoc attribute for "since": ${config}`)
return true
}
return ReleaseVersion.cmp(release, config as ReleaseVersion) >= 0
},
})
mcdoc.runtime.registerAttribute(meta, 'until', mcdoc.runtime.attribute.validator.string, {
filterElement: (config, ctx) => {
if (!config.startsWith('1.')) {
ctx.logger.warn(`Invalid mcdoc attribute for "until": ${config}`)
return true
}
return ReleaseVersion.cmp(release, config as ReleaseVersion) < 0
},
})
mcdoc.runtime.registerAttribute(
meta,
'deprecated',
mcdoc.runtime.attribute.validator.optional(mcdoc.runtime.attribute.validator.string),
{
mapField: (config, field, ctx) => {
if (config === undefined) {
return { ...field, deprecated: true }
}
if (!config.startsWith('1.')) {
ctx.logger.warn(`Invalid mcdoc attribute for "deprecated": ${config}`)
return field
}
if (ReleaseVersion.cmp(release, config as ReleaseVersion) >= 0) {
return { ...field, deprecated: true }
}
return field
},
},
)
const packFormats = new Map<number, McmetaVersion>()
for (const version of versions) {
if (version.type === 'release' && !packFormats.has(version.data_pack_version)) {
packFormats.set(version.data_pack_version, version)
}
}
mcdoc.runtime.registerAttribute(meta, 'pack_format', () => undefined, {
checker: (_, typeDef) => {
if (typeDef.kind !== 'literal' || typeof typeDef.value.value !== 'number') {
return undefined
}
const target = typeDef.value.value
return (node, ctx) => {
const targetVersion = packFormats.get(target)
if (!targetVersion) {
ctx.err.report(
localize('java-edition.pack-format.unsupported', target),
node,
core.ErrorSeverity.Warning,
)
} else if (targetVersion.id !== release) {
ctx.err.report(
localize('java-edition.pack-format.not-loaded', target, release),
node,
core.ErrorSeverity.Warning,
)
}
}
},
numericCompleter: (_, ctx) => {
return [...packFormats.values()].map((v, i) => ({
range: core.Range.create(ctx.offset),
label: `${v.data_pack_version}`,
labelSuffix: ` (${v.id})`,
sortText: `${i}`.padStart(4, '0'),
} satisfies core.CompletionItem))
},
})
registerMcdocAttributes(meta, release)
registerPackFormatAttribute(meta, release, versions)

json.initialize(ctx)
jeJson.initialize(ctx)
Expand Down
91 changes: 91 additions & 0 deletions packages/java-edition/src/mcdocAttributes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import * as core from '@spyglassmc/core'
import { localize } from '@spyglassmc/locales'
import * as mcdoc from '@spyglassmc/mcdoc'
import type { McmetaVersion, McmetaVersions } from './dependency'
import { ReleaseVersion } from './dependency'

export function registerMcdocAttributes(meta: core.MetaRegistry, release: ReleaseVersion) {
mcdoc.runtime.registerAttribute(meta, 'since', mcdoc.runtime.attribute.validator.string, {
filterElement: (config, ctx) => {
if (!config.startsWith('1.')) {
ctx.logger.warn(`Invalid mcdoc attribute for "since": ${config}`)
return true
}
return ReleaseVersion.cmp(release, config as ReleaseVersion) >= 0
},
})
mcdoc.runtime.registerAttribute(meta, 'until', mcdoc.runtime.attribute.validator.string, {
filterElement: (config, ctx) => {
if (!config.startsWith('1.')) {
ctx.logger.warn(`Invalid mcdoc attribute for "until": ${config}`)
return true
}
return ReleaseVersion.cmp(release, config as ReleaseVersion) < 0
},
})
mcdoc.runtime.registerAttribute(
meta,
'deprecated',
mcdoc.runtime.attribute.validator.optional(mcdoc.runtime.attribute.validator.string),
{
mapField: (config, field, ctx) => {
if (config === undefined) {
return { ...field, deprecated: true }
}
if (!config.startsWith('1.')) {
ctx.logger.warn(`Invalid mcdoc attribute for "deprecated": ${config}`)
return field
}
if (ReleaseVersion.cmp(release, config as ReleaseVersion) >= 0) {
return { ...field, deprecated: true }
}
return field
},
},
)
}

export function registerPackFormatAttribute(
meta: core.MetaRegistry,
release: ReleaseVersion,
versions: McmetaVersions,
) {
const packFormats = new Map<number, McmetaVersion>()
for (const version of versions) {
if (version.type === 'release' && !packFormats.has(version.data_pack_version)) {
packFormats.set(version.data_pack_version, version)
}
}
mcdoc.runtime.registerAttribute(meta, 'pack_format', () => undefined, {
checker: (_, typeDef) => {
if (typeDef.kind !== 'literal' || typeof typeDef.value.value !== 'number') {
return undefined
}
const target = typeDef.value.value
return (node, ctx) => {
const targetVersion = packFormats.get(target)
if (!targetVersion) {
ctx.err.report(
localize('java-edition.pack-format.unsupported', target),
node,
core.ErrorSeverity.Warning,
)
} else if (targetVersion.id !== release) {
ctx.err.report(
localize('java-edition.pack-format.not-loaded', target, release),
node,
core.ErrorSeverity.Warning,
)
}
}
},
numericCompleter: (_, ctx) => {
return [...packFormats.values()].map((v, i) => ({
range: core.Range.create(ctx.offset),
label: `${v.data_pack_version}`,
labelSuffix: ` (${v.id})`,
sortText: `${i}`.padStart(4, '0'),
} satisfies core.CompletionItem))
},
})
}
21 changes: 17 additions & 4 deletions packages/json/src/formatter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ import { indentFormatter } from '@spyglassmc/core'
import type {
JsonArrayNode,
JsonBooleanNode,
JsonFileNode,
JsonNullNode,
JsonNumberNode,
JsonObjectNode,
JsonStringNode,
} from '../node/index.js'

const file: Formatter<JsonFileNode> = (node, ctx) => {
const child = node.children[0]
return ctx.meta.getFormatter(child.type)(child, ctx)
}

const array: Formatter<JsonArrayNode> = (node, ctx) => {
if (node.children.length === 0) {
return '[]'
Expand All @@ -27,22 +33,29 @@ const object: Formatter<JsonObjectNode> = (node, ctx) => {
return '{}'
}
const fields = node.children.map((child) => {
const key = child.key && core.formatter.string(child.key, ctx)
const key = child.key && string(child.key, ctx)
const value = child.value
&& ctx.meta.getFormatter(child.value.type)(child.value, indentFormatter(ctx))
return `${ctx.indent(1)}${key ?? ''}: ${value ?? ''}`
})
return `{\n${fields.join(',\n')}\n${ctx.indent()}}`
}

const number: Formatter<JsonNumberNode> = (node, ctx) =>
ctx.meta.getFormatter(node.value.type)(node.value, ctx)
const number: Formatter<JsonNumberNode> = (node, ctx) => {
return ctx.meta.getFormatter(node.value.type)(node.value, ctx)
}

const string: Formatter<JsonStringNode> = (node, ctx) => {
// TODO: Use core.formatter.string when it correctly escapes the string
return JSON.stringify(node.value)
}

export function register(meta: MetaRegistry): void {
meta.registerFormatter<JsonFileNode>('json:file', file)
meta.registerFormatter<JsonArrayNode>('json:array', array)
meta.registerFormatter<JsonBooleanNode>('json:boolean', core.formatter.boolean)
meta.registerFormatter<JsonNullNode>('json:null', () => 'null')
meta.registerFormatter<JsonNumberNode>('json:number', number)
meta.registerFormatter<JsonObjectNode>('json:object', object)
meta.registerFormatter<JsonStringNode>('json:string', core.formatter.string)
meta.registerFormatter<JsonStringNode>('json:string', string)
}
1 change: 1 addition & 0 deletions packages/locales/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"integer": "an integer",
"integer.between": "an integer between %0% and %1%",
"invalid-key-combination": "Invalid combination of keys %0%",
"invalid-regex-pattern": "Invalid regex pattern: %0%",
"java-edition.binder.wrong-folder": "Files in the %0% folder are not recognized in loaded version %1%, did you meant to use the %2% folder?",
"java-edition.binder.wrong-version": "Files in the %0% folder are not recognized in loaded version %1%",
"java-edition.pack-format.unsupported": "Pack format %0% does not have a corresponding release version. Snapshot versions are unsupported.",
Expand Down
19 changes: 19 additions & 0 deletions packages/mcdoc/src/runtime/attribute/builtin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,23 @@ export function registerBuiltinAttributes(meta: core.MetaRegistry) {
}
},
})
registerAttribute(meta, 'regex_pattern', () => undefined, {
checker: (_, typeDef) => {
if (typeDef.kind !== 'literal' || typeDef.value.kind !== 'string') {
return undefined
}
const pattern = typeDef.value.value
return (node, ctx) => {
try {
RegExp(pattern)
} catch (e) {
const message = e instanceof Error ? e.message : `${e}`
const error = message
.replace(/^Invalid regular expression: /, '')
.replace(/^\/.+\/: /, '')
ctx.err.report(localize('invalid-regex-pattern', error), node, 2)
}
}
},
})
}
2 changes: 1 addition & 1 deletion packages/nbt/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type * as core from '@spyglassmc/core'
import { registerMcdocAttributes } from './attributes.js'
import * as checker from './checker/index.js'
import * as colorizer from './colorizer/index.js'
import * as completer from './completer/index.js'
import { registerMcdocAttributes } from './mcdocAttributes.js'
import type { NbtCompoundNode, NbtNode, NbtPathNode } from './node/index.js'
import * as parser from './parser/index.js'

Expand Down
File renamed without changes.

0 comments on commit 65355b1

Please sign in to comment.