mirror of
https://github.com/latex-lsp/texlab.git
synced 2025-08-04 02:39:21 +00:00
Move citeproc into a separate crate
This commit is contained in:
parent
bacbcdb824
commit
5e612219d1
19 changed files with 70 additions and 15 deletions
20
crates/texlab_citeproc/Cargo.toml
Normal file
20
crates/texlab_citeproc/Cargo.toml
Normal file
|
@ -0,0 +1,20 @@
|
|||
[package]
|
||||
name = "texlab-citeproc"
|
||||
version = "0.1.0"
|
||||
authors = [
|
||||
"Eric Förster <efoerster@users.noreply.github.com>",
|
||||
"Patrick Förster <pfoerster@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
futures-preview = { version = "0.3.0-alpha.15", features = ["compat"] }
|
||||
html2md = "0.2.9"
|
||||
lsp-types = { git = "https://github.com/latex-lsp/lsp-types", rev = "9fcc5d9b9d3013ce84e20ef566267754d594b268", features = ["proposed"] }
|
||||
runtime = "0.3.0-alpha.4"
|
||||
runtime-tokio = "0.3.0-alpha.4"
|
||||
serde = { version = "1.0.97", features = ["derive", "rc"] }
|
||||
tempfile = "3"
|
||||
texlab-syntax = { path = "../texlab_syntax" }
|
||||
tokio = "0.1"
|
||||
tokio-process = "0.2.4"
|
||||
|
20
crates/texlab_citeproc/build.rs
Normal file
20
crates/texlab_citeproc/build.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use std::process::Command;
|
||||
|
||||
fn sh(command: &'static str) {
|
||||
let (executable, args) = if cfg!(windows) {
|
||||
("cmd", vec!["/C", command])
|
||||
} else {
|
||||
("sh", vec!["-c", command])
|
||||
};
|
||||
|
||||
Command::new(executable)
|
||||
.args(args)
|
||||
.current_dir("script")
|
||||
.output()
|
||||
.expect(&format!("Failed to execute \"{}\"", command));
|
||||
}
|
||||
|
||||
fn main() {
|
||||
sh("npm ci");
|
||||
sh("npm run dist");
|
||||
}
|
93
crates/texlab_citeproc/script/.gitignore
vendored
Normal file
93
crates/texlab_citeproc/script/.gitignore
vendored
Normal file
|
@ -0,0 +1,93 @@
|
|||
|
||||
# Created by https://www.gitignore.io/api/node
|
||||
# Edit at https://www.gitignore.io/?templates=node
|
||||
|
||||
### Node ###
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# End of https://www.gitignore.io/api/node
|
||||
|
||||
# TypeScript output
|
||||
out/
|
||||
|
||||
# dist
|
||||
dist/
|
5
crates/texlab_citeproc/script/.prettierrc
Normal file
5
crates/texlab_citeproc/script/.prettierrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"printWidth": 80,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
4549
crates/texlab_citeproc/script/package-lock.json
generated
Normal file
4549
crates/texlab_citeproc/script/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
31
crates/texlab_citeproc/script/package.json
Normal file
31
crates/texlab_citeproc/script/package.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "texlab-citeproc",
|
||||
"version": "0.1.0",
|
||||
"description": "LaTeX Language Server",
|
||||
"repository": "https://github.com/latex-lsp/texlab.git",
|
||||
"author": "Eric Förster <efoerster@users.noreply.github.com>",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dist": "webpack",
|
||||
"build": "tsc -p .",
|
||||
"watch": "tsc -p . --watch",
|
||||
"lint": "tslint --project .",
|
||||
"format": "prettier --write \"src/**/*.{ts,json}\" \"*.{ts,json,yml,md}\" \".vscode/**/*.{json}\""
|
||||
},
|
||||
"devDependencies": {
|
||||
"@citation-js/core": "^0.4.8",
|
||||
"@citation-js/plugin-bibtex": "^0.4.8",
|
||||
"@citation-js/plugin-csl": "^0.4.8",
|
||||
"@types/node": "^11.13.17",
|
||||
"@types/webpack": "^4.4.35",
|
||||
"null-loader": "^0.1.1",
|
||||
"prettier": "^1.18.2",
|
||||
"ts-loader": "^5.4.5",
|
||||
"ts-node": "^8.3.0",
|
||||
"tslint": "^5.18.0",
|
||||
"tslint-config-prettier": "^1.15.0",
|
||||
"typescript": "^3.5.3",
|
||||
"webpack": "^4.35.3",
|
||||
"webpack-cli": "^3.3.6"
|
||||
}
|
||||
}
|
7
crates/texlab_citeproc/script/src/citation-js.d.ts
vendored
Normal file
7
crates/texlab_citeproc/script/src/citation-js.d.ts
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
declare module '@citation-js/core' {
|
||||
export class Cite {
|
||||
constructor(text: string);
|
||||
|
||||
public format(type: string, options: any): string;
|
||||
}
|
||||
}
|
13
crates/texlab_citeproc/script/src/main.ts
Normal file
13
crates/texlab_citeproc/script/src/main.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { Cite } from '@citation-js/core';
|
||||
import '@citation-js/plugin-bibtex';
|
||||
import '@citation-js/plugin-csl';
|
||||
import fs from 'fs';
|
||||
|
||||
const code = fs.readFileSync('entry.bib').toString();
|
||||
const cite = new Cite(code);
|
||||
const html = cite.format('bibliography', {
|
||||
format: 'html',
|
||||
template: 'apa',
|
||||
lang: 'en-US',
|
||||
});
|
||||
console.log(html);
|
15
crates/texlab_citeproc/script/tsconfig.json
Normal file
15
crates/texlab_citeproc/script/tsconfig.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"lib": ["es6"],
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
20
crates/texlab_citeproc/script/tslint.json
Normal file
20
crates/texlab_citeproc/script/tslint.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"extends": ["tslint:latest", "tslint-config-prettier"],
|
||||
"rules": {
|
||||
"no-implicit-dependencies": false,
|
||||
"interface-name": false,
|
||||
"max-classes-per-file": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"variable-name": [
|
||||
true,
|
||||
"ban-keywords",
|
||||
"check-format",
|
||||
"allow-leading-underscore",
|
||||
"allow-pascal-case"
|
||||
],
|
||||
"no-empty": false,
|
||||
"no-console": false,
|
||||
"no-conditional-assignment": false,
|
||||
"no-bitwise": false
|
||||
}
|
||||
}
|
37
crates/texlab_citeproc/script/webpack.config.ts
Normal file
37
crates/texlab_citeproc/script/webpack.config.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
import path from 'path';
|
||||
import { Configuration } from 'webpack';
|
||||
|
||||
const config: Configuration = {
|
||||
target: 'node',
|
||||
entry: './src/main.ts',
|
||||
mode: 'production',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'citeproc.js',
|
||||
libraryTarget: 'commonjs2',
|
||||
devtoolModuleFilenameTemplate: '../[resource-path]',
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.js', '.json'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: 'ts-loader',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
// Map browser dependencies to an empty module
|
||||
test: /node_modules[/\\](sync-request|isomorphic-fetch|ws)[/\\]/,
|
||||
use: 'null-loader',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
90
crates/texlab_citeproc/src/lib.rs
Normal file
90
crates/texlab_citeproc/src/lib.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
#![feature(async_await)]
|
||||
|
||||
use texlab_syntax::*;
|
||||
use futures::compat::*;
|
||||
use lsp_types::*;
|
||||
use std::process::{Command, Stdio};
|
||||
use tempfile::tempdir;
|
||||
use tokio_process::CommandExt;
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum RenderCitationError {
|
||||
InitializationFailed,
|
||||
InvalidEntry,
|
||||
NodeNotInstalled,
|
||||
ScriptFaulty,
|
||||
InvalidOutput,
|
||||
}
|
||||
|
||||
pub async fn render_citation(entry_code: &str) -> Result<MarkupContent, RenderCitationError> {
|
||||
let tree = BibtexSyntaxTree::from(entry_code);
|
||||
if tree.entries().iter().any(|entry| entry.fields.len() == 0) {
|
||||
return Err(RenderCitationError::InvalidEntry);
|
||||
}
|
||||
|
||||
let directory = tempdir().map_err(|_| RenderCitationError::InitializationFailed)?;
|
||||
let entry_path = directory.path().join("entry.bib");
|
||||
tokio::fs::write(entry_path, &entry_code)
|
||||
.compat()
|
||||
.await
|
||||
.map_err(|_| RenderCitationError::InitializationFailed)?;
|
||||
|
||||
let mut process = Command::new("node")
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.current_dir(directory.path())
|
||||
.spawn_async()
|
||||
.map_err(|_| RenderCitationError::NodeNotInstalled)?;
|
||||
|
||||
tokio::io::write_all(process.stdin().as_mut().unwrap(), SCRIPT)
|
||||
.compat()
|
||||
.await
|
||||
.map_err(|_| RenderCitationError::ScriptFaulty)?;
|
||||
|
||||
let output = process
|
||||
.wait_with_output()
|
||||
.compat()
|
||||
.await
|
||||
.map_err(|_| RenderCitationError::ScriptFaulty)?;
|
||||
|
||||
if output.status.success() {
|
||||
let html =
|
||||
String::from_utf8(output.stdout).map_err(|_| RenderCitationError::InvalidOutput)?;
|
||||
let markdown = html2md::parse_html(&html);
|
||||
Ok(MarkupContent {
|
||||
kind: MarkupKind::Markdown,
|
||||
value: markdown.trim().to_owned().into(),
|
||||
})
|
||||
} else {
|
||||
Err(RenderCitationError::InvalidEntry)
|
||||
}
|
||||
}
|
||||
|
||||
const SCRIPT: &str = include_str!("../script/dist/citeproc.js");
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[runtime::test(runtime_tokio::Tokio)]
|
||||
async fn test_valid() {
|
||||
let markdown =
|
||||
render_citation("@article{foo, author = {Foo Bar}, title = {Baz Qux}, year = 1337}")
|
||||
.await;
|
||||
assert_eq!(markdown.unwrap().value, "Bar, F. (1337). Baz Qux.");
|
||||
}
|
||||
|
||||
#[runtime::test(runtime_tokio::Tokio)]
|
||||
async fn test_invalid() {
|
||||
let markdown = render_citation("@article{}").await;
|
||||
assert_eq!(markdown, Err(RenderCitationError::InvalidEntry));
|
||||
}
|
||||
|
||||
#[runtime::test(runtime_tokio::Tokio)]
|
||||
async fn test_empty() {
|
||||
let markdown = render_citation("@article{foo,}").await;
|
||||
assert_eq!(markdown, Err(RenderCitationError::InvalidEntry));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue