This commit is contained in:
Emiliano Heyns
2021-04-05 00:37:08 +02:00
parent 4f6679fd25
commit 9177d60c48
35 changed files with 216 additions and 169 deletions

View File

@@ -1,3 +1,5 @@
import type { XUL } from '../typings/xul'
declare const document: any
declare const window: any
declare const Zotero: any

View File

@@ -5,6 +5,8 @@ declare const Zotero: any
Components.utils.import('resource://gre/modules/FileUtils.jsm')
declare const FileUtils: any
import type { XUL } from '../typings/xul'
// import { OS } from '../typings/xpcom'
import { clean_pane_persist, patch as $patch$ } from './monkey-patch'
import { flash } from './flash'
@@ -288,7 +290,7 @@ import * as DateParser from './dateparser'
import { qualityReport } from './qr-check'
import { titleCase } from './case'
import { HTMLParser } from './markupparser'
import { ParsedDate } from './typings/bbt'
import type { ParsedDate } from './dateparser'
Zotero.Translate.Export.prototype.Sandbox.BetterBibTeX = {
qrCheck(_sandbox: any, value: string, test: string, params = null) { return qualityReport(value, test, params) },
@@ -657,9 +659,9 @@ class Progress {
}
else {
document.getElementById('better-bibtex-startup').hidden = false
this.progressmeter = (document.getElementById('better-bibtex-startup-progress') as XUL.ProgressMeter)
this.progressmeter = (document.getElementById('better-bibtex-startup-progress') as unknown as XUL.ProgressMeter)
this.progressmeter.value = 0
this.label = (document.getElementById('better-bibtex-startup-label') as XUL.Label)
this.label = (document.getElementById('better-bibtex-startup-label') as unknown as XUL.Label)
this.label.value = msg
}
}

View File

@@ -5,7 +5,22 @@ import edtfy = require('edtfy')
// import escapeStringRegexp = require('escape-string-regexp')
import * as months from '../gen/dateparser-months.json'
import { ParsedDate } from './typings/bbt'
export type ParsedDate = {
type?: 'date' | 'open' | 'verbatim' | 'season' | 'interval' | 'list'
year?: number
month?: number
day?: number
orig?: ParsedDate
verbatim?: string
from?: ParsedDate
to?: ParsedDate
dates?: ParsedDate[]
season?: number
uncertain?: boolean
approximate?: boolean
}
const months_re = new RegExp(Object.keys(months).sort((a, b) => b.length - a.length).join('|'), 'i')
/*

View File

@@ -5,6 +5,7 @@ declare const Components: any
declare const Services: any
import { log } from '../logger'
import 'xpcom'
Components.utils.import('resource://gre/modules/osfile.jsm')

View File

@@ -1,3 +1,5 @@
import type { MarkupNode } from '../typings/markup'
import parse5 = require('parse5/lib/parser')
const htmlParser = new parse5({ sourceCodeLocationInfo: true })
import { titleCase } from './case'
@@ -93,10 +95,10 @@ export const HTMLParser = new class { // eslint-disable-line @typescript-eslint/
private html: string
private ligatures = new RegExp(`[${Object.keys(ligatures).join('')}]`, 'g')
public parse(html, options: HTMLParserOptions): IZoteroMarkupNode {
public parse(html, options: HTMLParserOptions): MarkupNode {
this.html = html
let doc: IZoteroMarkupNode
let doc: MarkupNode
this.caseConversion = options.caseConversion
this.braceProtection = options.caseConversion && options.exportBraceProtection
@@ -155,7 +157,7 @@ export const HTMLParser = new class { // eslint-disable-line @typescript-eslint/
return doc
}
private titleCase(node: IZoteroMarkupNode) {
private titleCase(node: MarkupNode) {
if (node.nodeName === '#text') {
node.value = this.titleCased.substr(node.titleCased, node.value.length)
return
@@ -167,7 +169,7 @@ export const HTMLParser = new class { // eslint-disable-line @typescript-eslint/
}
}
private unwrapSpurious(node: IZoteroMarkupNode) {
private unwrapSpurious(node: MarkupNode) {
// debug('spurious:', { nodeName: node.nodeName, attrs: Object.keys(node.attr).length, nocase: node.nocase, childNodes: node.childNodes.length })
if (node.nodeName === '#text') return node
@@ -180,7 +182,7 @@ export const HTMLParser = new class { // eslint-disable-line @typescript-eslint/
}
// BibLaTeX is beyond insane https://github.com/retorquere/zotero-better-bibtex/issues/541#issuecomment-240999396
private unwrapNocase(node: IZoteroMarkupNode): IZoteroMarkupNode[] {
private unwrapNocase(node: MarkupNode): MarkupNode[] {
if (node.nodeName === '#text') return [ node ]
// unwrap and flatten
@@ -205,7 +207,7 @@ export const HTMLParser = new class { // eslint-disable-line @typescript-eslint/
})
}
private cleanupNocase(node: IZoteroMarkupNode, nocased = false): IZoteroMarkupNode[] {
private cleanupNocase(node: MarkupNode, nocased = false): MarkupNode[] {
if (node.nodeName === '#text') return null
if (nocased) delete node.nocase
@@ -215,7 +217,7 @@ export const HTMLParser = new class { // eslint-disable-line @typescript-eslint/
}
}
private collectText(node: IZoteroMarkupNode) {
private collectText(node: MarkupNode) {
switch (node.nodeName) {
case '#text':
node.titleCased = this.titleCased.length
@@ -237,7 +239,7 @@ export const HTMLParser = new class { // eslint-disable-line @typescript-eslint/
}
}
private plaintext(childNodes: IZoteroMarkupNode[], text, offset) {
private plaintext(childNodes: MarkupNode[], text, offset) {
// replace ligatures so titlecasing works for things like "figures"
text = text.replace(this.ligatures, (ligature: string) => (ligatures[ligature] as string))
const l = childNodes.length
@@ -267,7 +269,7 @@ export const HTMLParser = new class { // eslint-disable-line @typescript-eslint/
private walk(node, isNocased = false) {
// debug('walk:', node.nodeName)
const normalized_node: IZoteroMarkupNode = { nodeName: node.nodeName, childNodes: [], attr: {}, class: {} }
const normalized_node: MarkupNode = { nodeName: node.nodeName, childNodes: [], attr: {}, class: {} }
for (const {name, value} of (node.attrs || [])) {
normalized_node.attr[name] = value
}

View File

@@ -11,6 +11,7 @@ declare class ChromeWorker extends Worker { }
Components.utils.import('resource://zotero/config.js')
declare const ZOTERO_CONFIG: any
import type { Translators as Translator } from '../typings/translators'
import { Preference } from '../gen/preferences'
import { Serializer } from './serializer'
import { log } from './logger'
@@ -84,9 +85,9 @@ const trace: Trace[] = []
// export singleton: https://k94n.com/es6-modules-single-instance-pattern
export const Translators = new class { // eslint-disable-line @typescript-eslint/naming-convention,no-underscore-dangle,id-blacklist,id-match
public byId: Record<string, ITranslatorHeader>
public byName: Record<string, ITranslatorHeader>
public byLabel: Record<string, ITranslatorHeader>
public byId: Record<string, Translator.Header>
public byName: Record<string, Translator.Header>
public byLabel: Record<string, Translator.Header>
public itemType: { note: number, attachment: number, annotation: number }
private queue = new Queue
@@ -314,7 +315,7 @@ export const Translators = new class { // eslint-disable-line @typescript-eslint
return this.exportItems(translatorID, displayOptions, job.scope, job.path)
}
const config: BBTWorker.Config = {
const config: Translator.Worker.Config = {
preferences: { ...Preference.all, ...job.preferences },
options: displayOptions || {},
items: [],
@@ -324,7 +325,7 @@ export const Translators = new class { // eslint-disable-line @typescript-eslint
}
let items: any[] = []
worker.onmessage = (e: { data: BBTWorker.Message }) => {
worker.onmessage = (e: { data: Translator.Worker.Message }) => {
switch (e.data?.kind) {
case 'error':
log.status({error: true, translator: translator.label, worker: id}, 'QBW failed:', Date.now() - start, e.data)

View File

@@ -1,14 +0,0 @@
export type ParsedDate = {
type?: 'date' | 'open' | 'verbatim' | 'season' | 'interval' | 'list'
year?: number
month?: number
day?: number
orig?: ParsedDate
verbatim?: string
from?: ParsedDate
to?: ParsedDate
dates?: ParsedDate[]
season?: number
uncertain?: boolean
approximate?: boolean
}

View File

@@ -1,8 +0,0 @@
interface ITranslatorHeader {
translatorID: string
label: string
target: string
configOptions?: {
getCollections?: boolean
}
}

View File

@@ -1,22 +0,0 @@
namespace OS {
namespace File {
function exists(path: string): Promise<boolean>
function read(path: string, options: { encoding: string } ): Promise<string>
function move(from: string, to: string): Promise<void>
function remove(path: string, options?: { ignoreAbsent: boolean }): Promise<void>
function writeAtomic(path: string, data: string, options: { tmpPath: string, encoding: string }): Promise<void>
function makeDir(path: string, options: { ignoreExisting: boolean }): Promise<void>
function stat(path: string): { isDir: boolean, size: number, unixMode?: number }
class DirectoryIterator {
constructor(path: string)
forEach(handler: any): Promise<void>
}
}
namespace Path {
function join(...args: string[]): string
function dirname(path: string): string
function basename(path: string): string
}
}

View File

@@ -17,14 +17,16 @@
"releaseURL": "https://github.com/retorquere/zotero-better-bibtex/releases/download/release/"
},
"scripts": {
"par": "tmux new-session 'npm run esbuild' \\; split-window 'npm run tsc' \\; split-window 'npm run lint'",
"pretest": "npm run build",
"test": "./test/behave --stop",
"lint": "eslint . --ext .ts",
"webpack": "webpack",
"setup": "./setup/setup.py && ts-node setup/index.ts",
"prebuild": "pnpm install && npm run setup && npm run lint && npm run tsc",
"prebuild": "pnpm install && npm run setup && npm run lint",
"tsc": "tsc --noEmit",
"build": "node esbuild.js",
"esbuild": "node esbuild.js",
"build": "npm run webpack",
"postbuild": "./util/patch-install-rdf.py && npm run zipup-better-bibtex && npm run zipup-debug-bridge",
"zipup-better-bibtex": "zotero-plugin-zipup build zotero-better-bibtex",
"zipup-debug-bridge": "zotero-plugin-zipup test/fixtures/debug-bridge debug-bridge",

View File

@@ -1,7 +1,7 @@
/* eslint-disable id-blacklist, @typescript-eslint/no-unsafe-return, @typescript-eslint/explicit-module-boundary-types */
import { client } from '../../content/client'
import { ZoteroTranslator } from '../typings/serialized-item'
import { Item } from '../typings/serialized-item'
const jurism = client === 'jurism'
const zotero = !jurism
@@ -85,7 +85,7 @@ function unalias(item: any) {
}
// import & export translators expect different creator formats... nice
export function simplifyForExport(item: any, dropAttachments = false): ZoteroTranslator.Item {
export function simplifyForExport(item: any, dropAttachments = false): Item {
unalias(item)
if (item.filingDate) item.filingDate = item.filingDate.replace(/^0000-00-00 /, '')
@@ -109,10 +109,10 @@ export function simplifyForExport(item: any, dropAttachments = false): ZoteroTra
item.attachments = (!dropAttachments && item.attachments) || []
}
return (item as ZoteroTranslator.Item)
return (item as Item)
}
export function simplifyForImport(item: any): ZoteroTranslator.Item {
export function simplifyForImport(item: any): Item {
unalias(item)
if (item.creators) {
@@ -129,5 +129,5 @@ export function simplifyForImport(item: any): ZoteroTranslator.Item {
if (!jurism) delete item.multi
return (item as ZoteroTranslator.Item)
return (item as Item)
}

View File

@@ -7,8 +7,8 @@ import { Events } from '../content/events'
declare const Zotero: any
const prefix = '${prefix}'
import * as preferences from './preferences.json'
import * as meta from '../content/prefs-meta.ts'
import { fromEntries } from '../content/object.ts'
import * as meta from '../content/prefs-meta'
import { fromEntries } from '../content/object'
<%
for pref in preferences:

View File

@@ -50,7 +50,7 @@ with open(os.path.join(root, 'gen/preferences.json')) as f:
variables.labels = translators.byLabel.keys()
template = """
interface ITranslator {
export interface ITranslator {
preferences: IPreferences
skipFields: string[]
skipField: {[key: string]: boolean}

View File

@@ -2,7 +2,7 @@ declare const Zotero: any
import { Translator } from './lib/translator'
export { Translator }
import { ZoteroTranslator } from '../gen/typings/serialized-item'
import { Item } from '../gen/typings/serialized-item'
import { Reference } from './bibtex/reference'
import { Exporter } from './bibtex/exporter'
@@ -287,7 +287,7 @@ export function doExport(): void {
// Zotero.write(`\n% ${Translator.header.label}\n`)
Zotero.write('\n')
let item: ZoteroTranslator.Item
let item: Item
while (item = Exporter.nextItem()) {
Zotero.debug(`exporting ${item.citationKey}`)
const ref = new Reference(item)

View File

@@ -3,7 +3,7 @@ declare const Zotero: any
import { Translator } from './lib/translator'
export { Translator }
import { ZoteroTranslator } from '../gen/typings/serialized-item'
import { Item } from '../gen/typings/serialized-item'
import { Exporter } from './bibtex/exporter'
@@ -143,7 +143,7 @@ const Mode = {
export function doExport(): void {
Translator.init('export')
let item: ZoteroTranslator.Item
let item: Item
const items = []
while ((item = Exporter.nextItem())) {
if (item.citationKey) items.push(item)

View File

@@ -2,7 +2,7 @@ declare const Zotero: any
import { log } from '../content/logger'
import { ZoteroTranslator } from '../gen/typings/serialized-item'
import { Item } from '../gen/typings/serialized-item'
const toWordsOrdinal = require('number-to-words/src/toWordsOrdinal')
function edition(n: string | number): string {
@@ -258,7 +258,7 @@ export function doExport(): void {
// Zotero.write(`\n% ${Translator.header.label}\n`)
Zotero.write('\n')
let item: ZoteroTranslator.Item
let item: Item
while (item = Exporter.nextItem()) {
const ref = new Reference(item)
if (item.itemType === 'report' && item.type?.toLowerCase().includes('manual')) ref.referencetype = 'manual'

View File

@@ -3,6 +3,7 @@ declare const Zotero: any
import YAML = require('js-yaml')
import { Translator } from './lib/translator'
import type { MarkupNode } from '../typings/markup'
export { Translator }
import { CSLExporter as Exporter } from './csl/csl'
@@ -17,7 +18,7 @@ const htmlConverter = new class HTML {
return this.markdown
}
private walk(tag: IZoteroMarkupNode) {
private walk(tag: MarkupNode) {
if (!tag) return
if (['#text', 'pre', 'script'].includes(tag.nodeName)) {

View File

@@ -7,12 +7,12 @@ export { Translator }
import { log } from '../content/logger'
import { fromEntries } from '../content/object'
import { ZoteroTranslator } from '../gen/typings/serialized-item'
import { Item } from '../gen/typings/serialized-item'
import * as escape from '../content/escape'
import * as Extra from '../content/extra'
function clean(item: ZoteroTranslator.Item): ZoteroTranslator.Item {
function clean(item: Item): Item {
item = {...item, ...Extra.get(item.extra, 'zotero') }
item.extra = item.extra.split('\n').filter(line => !line.match(/^OCLC:/i)).join('\n')
return item
@@ -20,7 +20,7 @@ function clean(item: ZoteroTranslator.Item): ZoteroTranslator.Item {
type ExpandedCollection = {
name: string
items: ZoteroTranslator.Item[]
items: Item[]
collections: ExpandedCollection[]
root: boolean
}
@@ -35,7 +35,7 @@ class Exporter {
public html = ''
constructor() {
const items: Record<number, ZoteroTranslator.Item> = {}
const items: Record<number, Item> = {}
const filed: Set<number> = new Set
const collections: Record<string, ExpandedCollection> = {}

View File

@@ -1,7 +1,8 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
import { ParsedDate } from '../../content/typings/bbt'
import type { ParsedDate } from '../../content/dateparser'
import { Translator } from '../lib/translator'
import type { Translators } from '../../typings/translators'
function pad(v:string, padding: string): string {
if (v.length >= padding.length) return v
@@ -48,7 +49,7 @@ function format(date) {
return formatted
}
export function datefield(date: ParsedDate, field: IField): IField {
export function datefield(date: ParsedDate, field: Translators.BibTeX.Field): Translators.BibTeX.Field {
field = JSON.parse(JSON.stringify({ ...field, value: '', enc: 'latex' }))
if (!date) return field

View File

@@ -1,12 +1,13 @@
declare const Zotero: any
import { Translator } from '../lib/translator'
import { ZoteroTranslator } from '../../gen/typings/serialized-item'
import { Item } from '../../gen/typings/serialized-item'
import { Cache } from '../../typings/cache'
import { JabRef } from '../bibtex/jabref' // not so nice... BibTeX-specific code
import * as itemfields from '../../gen/items/items'
import * as bibtexParser from '@retorquere/bibtex-parser'
import { Postfix } from '../bibtex/postfix.ts'
import { Postfix } from './postfix'
import * as Extra from '../../content/extra'
// export singleton: https://k94n.com/es6-modules-single-instance-pattern
@@ -40,10 +41,10 @@ export const Exporter = new class {
return uniq
}
public nextItem(): ZoteroTranslator.Item {
public nextItem(): Item {
this.postfix = this.postfix || (new Postfix(Translator.preferences.qualityReport))
let item: ZoteroTranslator.Item
let item: Item
while (item = Translator.nextItem()) {
if (['note', 'attachment'].includes(item.itemType)) continue
@@ -55,7 +56,7 @@ export const Exporter = new class {
this.jabref.citekeys.set(item.itemID, item.citationKey)
// this is not automatically lazy-evaluated?!?!
const cached: Types.DB.Cache.ExportedItem = item.cachable ? Zotero.BetterBibTeX.cacheFetch(item.itemID, Translator.options, Translator.preferences) : null
const cached: Cache.ExportedItem = item.cachable ? Zotero.BetterBibTeX.cacheFetch(item.itemID, Translator.options, Translator.preferences) : null
Translator.cache[cached ? 'hits' : 'misses'] += 1
if (cached) {

View File

@@ -1,18 +0,0 @@
export interface IField {
name: string
verbatim?: string
value: string | string[] | number | null | { path: string, title?: string, mimeType?: string } | { tag: string, type?: number }[]
enc?: 'raw' | 'url' | 'verbatim' | 'creators' | 'literal' | 'latex' | 'tags' | 'attachments' | 'date'
orig?: { name?: string, verbatim?: string, inherit?: boolean }
bibtexStrings?: boolean
bare?: boolean
raw?: boolean
// kept as seperate booleans for backwards compat
replace?: boolean
fallback?: boolean
html?: boolean
bibtex?: string
}

View File

@@ -3,7 +3,9 @@
declare const Zotero: any
import { ZoteroTranslator } from '../../gen/typings/serialized-item'
import { Item } from '../../gen/typings/serialized-item'
import { Cache } from '../../typings/cache'
import type { Translators } from '../../typings/translators'
import { Translator } from '../lib/translator'
@@ -296,7 +298,7 @@ const fieldOrder = [
*/
export class Reference {
public has: { [key: string]: any } = {}
public item: ZoteroTranslator.Item
public item: Item
public referencetype: string
public referencetype_source: string
public useprefix: boolean
@@ -340,7 +342,7 @@ export class Reference {
private _enc_creators_relax_marker = '\u200C' // zero-width non-joiner
private isBibString = /^[a-z][-a-z0-9_]*$/i
private metadata: Types.DB.Cache.ExportedItemMetadata = { DeclarePrefChars: '', noopsort: false, packages: [] }
private metadata: Cache.ExportedItemMetadata = { DeclarePrefChars: '', noopsort: false, packages: [] }
private packages: { [key: string]: boolean }
private juniorcomma: boolean
@@ -492,7 +494,7 @@ export class Reference {
* 'enc' means 'enc_latex'. If you pass both 'bibtex' and 'latex', 'bibtex' takes precedence (and 'value' will be
* ignored)
*/
public add(field: IField): string {
public add(field: Translators.BibTeX.Field): string {
if (Translator.preferences.testing && !this.inPostscript && field.name !== field.name.toLowerCase()) throw new Error(`Do not add mixed-case field ${field.name}`)
if (!field.value && !field.bibtex && this.inPostscript) {
@@ -676,7 +678,7 @@ export class Reference {
public hasCreator(type): boolean { return (this.item.creators || []).some(creator => creator.creatorType === type) }
public override(field: IField): void {
public override(field: Translators.BibTeX.Field): void {
const itemtype_name = field.name.split('.')
let name
if (itemtype_name.length === 2) {

View File

@@ -1,6 +1,7 @@
declare const Zotero: any
import { Translator } from '../lib/translator'
import type { MarkupNode } from '../../typings/markup'
import { log } from '../../content/logger'
import HE = require('he')
@@ -111,7 +112,7 @@ const htmlConverter = new class HTMLConverter {
this.stack = []
const ast: IZoteroMarkupNode = Zotero.BetterBibTeX.parseHTML(html, this.options)
const ast: MarkupNode = Zotero.BetterBibTeX.parseHTML(html, this.options)
this.walk(ast)
if (!options.commandspacers) this.latex = replace_command_spacers(this.latex)
@@ -127,7 +128,7 @@ const htmlConverter = new class HTMLConverter {
return { latex: this.latex, raw: ast.nodeName === 'pre', packages: Object.keys(this.packages) }
}
private walk(tag: IZoteroMarkupNode, nocased = false) {
private walk(tag: MarkupNode, nocased = false) {
if (!tag) return
switch (tag.nodeName) {

View File

@@ -7,6 +7,7 @@ import { Translator } from '../lib/translator'
import * as itemfields from '../../gen/items/items'
import * as Extra from '../../content/extra'
import { Cache } from '../../typings/cache'
import * as ExtraFields from '../../gen/items/extra-fields.json'
import { log } from '../../content/logger'
import { worker } from '../../content/worker'
@@ -53,7 +54,7 @@ export const CSLExporter = new class { // eslint-disable-line @typescript-eslint
order.push({ citationKey: item.citationKey, i: items.length })
let cached: Types.DB.Cache.ExportedItem
let cached: Cache.ExportedItem
if (cached = Zotero.BetterBibTeX.cacheFetch(item.itemID, Translator.options, Translator.preferences)) {
items.push(cached.reference)
continue

View File

@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return */
import { stringify } from '../../content/stringify'
import { ZoteroTranslator } from '../../gen/typings/serialized-item'
import { Item, Collection } from '../../gen/typings/serialized-item'
function rjust(str: string | number, width: number, padding: string): string {
if (typeof str === 'number') str = `${str}`
@@ -121,7 +121,7 @@ export function normalize(library: Library): void {
strip(item)
if (item.extra?.length) {
item.extra = (item as ZoteroTranslator.Item).extra.split('\n')
item.extra = (item as Item).extra.split('\n')
}
else {
delete item.extra
@@ -143,9 +143,9 @@ export function normalize(library: Library): void {
}, {})
if (library.collections && Object.keys(library.collections).length) {
const collectionOrder: ZoteroTranslator.Collection[] = Object.values(library.collections)
.sort((a: ZoteroTranslator.Collection, b: ZoteroTranslator.Collection): number => stringify({...a, key: '', parent: ''}).localeCompare(stringify({...b, key: '', parent: ''})))
const collectionKeys: Record<string, string> = collectionOrder.reduce((acc: Record<string, string>, coll: ZoteroTranslator.Collection, i: number): Record<string, string> => {
const collectionOrder: Collection[] = Object.values(library.collections)
.sort((a: Collection, b: Collection): number => stringify({...a, key: '', parent: ''}).localeCompare(stringify({...b, key: '', parent: ''})))
const collectionKeys: Record<string, string> = collectionOrder.reduce((acc: Record<string, string>, coll: Collection, i: number): Record<string, string> => {
coll.key = acc[coll.key] = `coll:${rjust(i, 5, '0')}` // eslint-disable-line no-magic-numbers
return acc
}, {})

View File

@@ -3,7 +3,8 @@ declare const ZOTERO_TRANSLATOR_INFO: any
import { defaults } from '../../content/prefs-meta'
import { client } from '../../content/client'
import { ZoteroTranslator } from '../../gen/typings/serialized-item'
import { Item, Collection } from '../../gen/typings/serialized-item'
import { ITranslator } from '../../gen/typings/translator'
import type { Preferences } from '../../gen/preferences'
import { log } from '../../content/logger'
@@ -21,7 +22,7 @@ const cacheDisabler = new class {
type NestedCollection = {
key: string
name: string
items: ZoteroTranslator.Item[]
items: Item[]
collections: NestedCollection[]
parent?: NestedCollection
}
@@ -103,12 +104,12 @@ export const Translator = new class implements ITranslator { // eslint-disable-l
public header: TranslatorHeader
public collections: Record<string, ZoteroTranslator.Collection>
public collections: Record<string, Collection>
private _items: {
remaining: ZoteroTranslator.Item[]
map: Record<number, ZoteroTranslator.Item>
remaining: Item[]
map: Record<number, Item>
}
private currentItem: ZoteroTranslator.Item
private currentItem: Item
public isJurisM: boolean
public isZotero: boolean
@@ -267,11 +268,11 @@ export const Translator = new class implements ITranslator { // eslint-disable-l
get collectionTree(): NestedCollection[] {
return Object.values(this.collections).filter(coll => !coll.parent).map(coll => this.nestedCollection(coll))
}
private nestedCollection(collection: ZoteroTranslator.Collection): NestedCollection {
private nestedCollection(collection: Collection): NestedCollection {
const nested: NestedCollection = {
key: collection.key,
name: collection.name,
items: collection.items.map((itemID: number) => this.items.map[itemID]).filter((item: ZoteroTranslator.Item) => item),
items: collection.items.map((itemID: number) => this.items.map[itemID]).filter((item: Item) => item),
collections: collection.collections.map((key: string) => this.nestedCollection(this.collections[key])).filter((coll: NestedCollection) => coll),
}
for (const coll of nested.collections) {
@@ -280,12 +281,12 @@ export const Translator = new class implements ITranslator { // eslint-disable-l
return nested
}
get items(): { remaining: ZoteroTranslator.Item[], map: Record<number, ZoteroTranslator.Item> } {
get items(): { remaining: Item[], map: Record<number, Item> } {
if (!this._items) {
const remaining: ZoteroTranslator.Item[] = []
const map: Record<number, ZoteroTranslator.Item> = {}
let item: ZoteroTranslator.Item
while (item = (Zotero.nextItem() as ZoteroTranslator.Item)) {
const remaining: Item[] = []
const map: Record<number, Item> = {}
let item: Item
while (item = (Zotero.nextItem() as Item)) {
item.cachable = this.cachable
item.journalAbbreviation = item.journalAbbreviation || item.autoJournalAbbreviation
remaining.push(map[item.itemID] = new Proxy(item, cacheDisabler))

View File

@@ -1,16 +0,0 @@
namespace BBTWorker {
type Config = {
preferences: any,
options: any,
items: ISerializedItem[]
collections: ZoteroCollection[]
cslItems?: Record<number, any>
cache: Record<number, {itemID: number, reference: string, metadata: any, meta: { updated: number }}>
}
type Message = { kind: 'done', output: boolean | string }
| { kind: 'debug', message: string }
| { kind: 'error', message: string }
| { kind: 'cache', itemID: number, reference: string, metadata: any }
| { kind: 'item', item: number }
}

View File

@@ -1,5 +1,8 @@
/* eslint-disable @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-assignment */
import { ITranslator } from '../../gen/typings/translator'
import type { Translators } from '../../typings/translators'
declare const doExport: () => void
declare const Translator: ITranslator
@@ -16,7 +19,7 @@ import { titleCase } from '../../content/case'
import * as itemCreators from '../../gen/items/creators.json'
import { client } from '../../content/client'
import { log } from '../../content/logger'
import { ZoteroTranslator } from '../../gen/typings/serialized-item'
import { Collection } from '../../gen/typings/serialized-item'
const ctx: DedicatedWorkerGlobalScope = self as any
@@ -180,7 +183,7 @@ function saveFile(path, overwrite) {
}
class WorkerZotero {
public config: BBTWorker.Config
public config: Translators.Worker.Config
public output: string
public exportDirectory: string
public exportFile: string
@@ -230,7 +233,7 @@ class WorkerZotero {
this.send({ kind: 'done', output: this.exportFile ? true : this.output })
}
public send(message: BBTWorker.Message) {
public send(message: Translators.Worker.Message) {
ctx.postMessage(message)
}
@@ -258,7 +261,7 @@ class WorkerZotero {
return this.config.items.shift()
}
public nextCollection(): ZoteroTranslator.Collection {
public nextCollection(): Collection {
return this.config.collections.shift()
}
@@ -282,7 +285,7 @@ class WorkerZotero {
export const Zotero = new WorkerZotero // eslint-disable-line @typescript-eslint/naming-convention,no-underscore-dangle,id-blacklist,id-match
export function onmessage(e: { data: BBTWorker.Config }): void {
export function onmessage(e: { data: Translators.Worker.Config }): void {
Zotero.BetterBibTeX.localeDateOrder = workerContext.localeDateOrder
if (e.data?.items && !Zotero.config) {

View File

@@ -15,18 +15,22 @@
"sourceMap": false,
"downlevelIteration": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"typeRoots": [
"./node_modules/@types",
"./gen/typings",
"./typings"
],
"lib": [ "es2017", "dom", "dom.iterable", "webworker" ]
},
"include": [
"content/**/*",
"translators/**/*",
"zotero-webpack/**/*",
"setup/**/*",
"gen/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts",
"typings"
"**/*.spec.ts"
]
}

View File

@@ -1,4 +1,4 @@
export namespace Cache {
export declare namespace Cache {
interface ExportedItemMetadata {
DeclarePrefChars: string
noopsort: boolean

View File

@@ -1,4 +1,4 @@
interface IZoteroMarkupNode {
export interface MarkupNode {
nodeName: string
childNodes?: IZoteroMarkupNode[]
attr?: { [key: string]: string }

51
typings/translators.d.ts vendored Normal file
View File

@@ -0,0 +1,51 @@
import { Item, Collection } from '../gen/typings/serialized-item'
export namespace Translators {
namespace Worker {
type Config = {
preferences: any,
options: any,
items: Item[]
collections: Collection[]
cslItems?: Record<number, any>
cache: Record<number, {itemID: number, reference: string, metadata: any, meta: { updated: number }}>
}
type Message =
{ kind: 'done', output: boolean | string }
| { kind: 'debug', message: string }
| { kind: 'error', message: string }
| { kind: 'cache', itemID: number, reference: string, metadata: any }
| { kind: 'item', item: number }
}
namespace BibTeX {
interface Field {
name: string
verbatim?: string
value: string | string[] | number | null | { path: string, title?: string, mimeType?: string } | { tag: string, type?: number }[]
enc?: 'raw' | 'url' | 'verbatim' | 'creators' | 'literal' | 'latex' | 'tags' | 'attachments' | 'date'
orig?: { name?: string, verbatim?: string, inherit?: boolean }
bibtexStrings?: boolean
bare?: boolean
raw?: boolean
// kept as seperate booleans for backwards compat
replace?: boolean
fallback?: boolean
html?: boolean
bibtex?: string
}
}
interface Header {
translatorID: string
label: string
target: string
configOptions?: {
getCollections?: boolean
}
}
}

26
typings/xpcom.d.ts vendored Normal file
View File

@@ -0,0 +1,26 @@
declare interface DirectoryIterator {
forEach: (handler: any) => Promise<void>
}
declare interface DirectoryIteratorConstructable {
new(path: string): DirectoryIterator
}
export declare const OS: {
File: {
exists: (path: string) => Promise<boolean>
read: (path: string, options: { encoding: string } ) => Promise<string>
move: (from: string, to: string) => Promise<void>
remove: (path: string, options?: { ignoreAbsent: boolean }) => Promise<void>
writeAtomic: (path: string, data: string, options: { tmpPath: string, encoding: string }) => Promise<void>
makeDir: (path: string, options: { ignoreExisting: boolean }) => Promise<void>
stat: (path: string) => { isDir: boolean, size: number, unixMode?: number }
DirectoryIterator: DirectoryIteratorConstructable
}
Path: {
join: (...args: string[]) => string
dirname: (path: string) => string
basename: (path: string) => string
}
}

View File

@@ -3,37 +3,45 @@ export namespace XUL {
public hidden: boolean
public getAttribute(name: string): string
public setAttribute(name: string, value: string): void
public classList: ClassList
}
class Label extends XUL.Element {
class Label extends Element {
public value: string
}
class Textbox extends XUL.Element {
public value: string
public readonly: boolean
}
class Checkbox extends XUL.Element {
public checked: boolean
}
class Menuitem extends XUL.Element {
public value: string
public label: string
}
class ProgressMeter extends XUL.Element {
public value: string | number
}
class Menupopup extends XUL.Element {
public children: Menuitem[]
}
class Menulist extends XUL.Element {
public firstChild: Menupopup
public selectedItem: Menuitem
public value: string
}
}
class ClassList {
public add(classname: string): void
public remove(classname: string): void
public contains(classname: string): boolean
}

View File

@@ -35,7 +35,7 @@ const common = {
},
resolve: {
extensions: ['.ts', '.js'],
extensions: ['.js', '.ts', '.d.ts'],
// https://github.com/webpack/webpack/pull/8460/commits/a68426e9255edcce7822480b78416837617ab065
fallback: {
fs: false,