Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Refactor to ES Modules #17

Merged
merged 1 commit into from
Oct 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
tab_width = 2
trim_trailing_whitespace = true

[*.md]
Expand Down
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
],
"args": [
"-p", "slt",
//"-j", "C:\\src\\sfm-utils\\samples\\56TIT.json"
"-j", "\\samples\\56TIT.json"
]
},
{
Expand Down
1,023 changes: 452 additions & 571 deletions package-lock.json

Large diffs are not rendered by default.

17 changes: 9 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"description": "Utility to convert text files to suitable SFM files for Paratext",
"bin": "dist/index.js",
"main": "dist/index",
"type": "module",
"scripts": {
"build": "npx tsc -p .",
"lint": "eslint . --ext .ts",
Expand All @@ -26,21 +27,21 @@
},
"homepage": "https://github.com/mseag/sfm-utils#readme",
"dependencies": {
"commander": "^7.0.0",
"node-unrtf": "^3.1.7",
"commander": "^11.1.0",
"node-unrtf": "^4.1.0",
"path": "^0.12.7"
},
"devDependencies": {
"@ava/typescript": "^3.0.1",
"@types/node": "^18.11.16",
"@typescript-eslint/eslint-plugin": "^5.46.1",
"@typescript-eslint/parser": "^5.46.1",
"@types/node": "^18.18.6",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
"ava": "^5.1.1",
"eslint": "^8.30.0",
"nodemon": "^2.0.20",
"eslint": "^8.51.0",
"nodemon": "^3.0.1",
"pkg": "^5.8.0",
"ts-node": "^10.9.1",
"typescript": "^4.9.4"
"typescript": "^5.2.2"
},
"ava": {
"extensions": [
Expand Down
16 changes: 8 additions & 8 deletions src/backTranslation.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Copyright 2023 SIL International
// Types and utilities for handling back translation rtf text file
import * as fs from 'fs';
import * as path from 'path'
import * as books from './books';
import * as books from './books.js';
import require from './cjs-require.js';
const {UnRTF } = require("node-unrtf");
import * as os from 'os';
import * as sfmConsole from './sfmConsole';
import * as toolbox from './toolbox';
import * as sfmConsole from './sfmConsole.js';
import * as toolbox from './toolbox.js';

/**
* Regex for line containing verse(s)
Expand Down Expand Up @@ -61,7 +61,7 @@ export async function updateObj(bookObj: books.objType, file: string, currentCha
if (!os.type().startsWith('Linux')) {
console.error("unRtf needs to run on Linux");
process.exit(1);
}
}
const unRtfPath = os.type().startsWith('Linux') ? "/usr/bin" : ""; // Path for UnRtf
const unRtf = new UnRTF(unRtfPath);
const options = {
Expand All @@ -77,7 +77,7 @@ export async function updateObj(bookObj: books.objType, file: string, currentCha

// Remove empty lines, along with rtf metadata and title
backTranslationData = backTranslationData.filter(item => item);
backTranslationData.forEach(l => {
backTranslationData.forEach(l => {
if (l.startsWith('###') || l.startsWith('AUTHOR:') || l.startsWith('---') || l.startsWith('Lem')) {
// Skip rtf metadata and title
return;
Expand Down Expand Up @@ -107,7 +107,7 @@ export async function updateObj(bookObj: books.objType, file: string, currentCha
//console.log('verse ' + verseMatch[1] + ': ' + verseMatch[2]);
} else {
// Parsing error. Possibly section header split a verse, so join with the last verse
let contentLength = bookObj.content[currentChapter].content.length;
const contentLength = bookObj.content[currentChapter].content.length;
if (contentLength > 1) {
bookObj.content[currentChapter].content[contentLength-2].text += ' (split section) ' + verse;
}
Expand Down Expand Up @@ -143,7 +143,7 @@ export async function updateObj(bookObj: books.objType, file: string, currentCha
if (bookObj.header.bookInfo.versesInChapter &&
bookObj.header.bookInfo.versesInChapter[currentChapter] != verseNum) {
s.log('warn', `${bookObj.header.bookInfo.name} ${currentChapter} expected ` +
`${bookObj.header.bookInfo.versesInChapter[currentChapter]} verses but got ${verseNum}`);
`${bookObj.header.bookInfo.versesInChapter[currentChapter]} verses but got ${verseNum}`);
}

}
6 changes: 6 additions & 0 deletions src/cjs-require.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Workaround to use ECMAScript modules
// From https://dev.to/caspergeek/how-to-use-require-in-ecmascript-modules-1l42
import { createRequire } from "module";
const require = createRequire(import.meta.url);

export default require;
2 changes: 1 addition & 1 deletion src/fileAssistant.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright 2022 SIL International
// Utilites for handling file paths
// Utilities for handling file paths
import * as fs from 'fs';
import * as path from 'path';

Expand Down
51 changes: 31 additions & 20 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
#!/usr/bin/env node
// Copyright 2022 SIL International
import * as program from 'commander';
// Copyright 2022-2023 SIL International
import { CommanderError, program } from 'commander';
import * as fs from 'fs';
import * as backTranslation from './backTranslation';
import * as books from './books';
import * as toolbox from './toolbox';
import * as sfm from './sfm';
import * as sfmConsole from './sfmConsole';
import * as fileAssistant from './fileAssistant';
const {version} = require('../package.json');
import * as backTranslation from './backTranslation.js';
import * as books from './books.js';
import * as toolbox from './toolbox.js';
import require from './cjs-require.js';
import * as sfm from './sfm.js';
import * as sfmConsole from './sfmConsole.js';
import * as fileAssistant from './fileAssistant.js';
//const {version} = require('../package.json');

////////////////////////////////////////////////////////////////////
// Get parameters
////////////////////////////////////////////////////////////////////
program
.version(version, '-v, --version', 'output the current version')
// .version(version, '-v, --version', 'output the current version')
.description("Utilities to 1) parse Toolbox text files into JSON Objects. " +
"2) take a JSON file and write out an .SFM file for Paratext.")
.option("-b, --back <path to single text file>", "path to back translation rtf text file")
Expand All @@ -25,7 +26,15 @@ program
.option("-p, --projectName <name>", "name of the Paratext project>")
.option("-bs, --backSuperDirectory <path to a directory containing directories for each book in a project>", "back translation - path to a directory containing directories for each book in a project")
.option("-s, --superDirectory <path to a directory containing directories for each book in a project>", "path to a directory containing directories for each book in a project")
.parse(process.argv);
.exitOverride();
try {
program.parse();
} catch (error: unknown) {
if (error instanceof CommanderError) {
console.error(error.message);
}
process.exit(1);
}

// Debugging parameters
const options = program.opts();
Expand Down Expand Up @@ -95,7 +104,7 @@ if (options.superDirectory && !fs.existsSync(options.superDirectory)) {
}

// Validate one of the optional parameters is given
if (!options.back && !options.text && !options.backDirectory && !options.directory &&
if (!options.back && !options.text && !options.backDirectory && !options.directory &&
!options.json && !options.backSuperDirectory && !options.superDirectory) {
console.error("Need to pass another optional parameter [-b -t -bd -d -j -bs or -s]");
process.exit(1);
Expand All @@ -118,7 +127,7 @@ if (options.json) {
processText(options.text, bookObj);
} else if (options.backDirectory) {
// Convert the RTF text files in a directory into an SFM book file
processBackDirectory(options.backDirectory);
processBackDirectory(options.backDirectory);
} else if (options.directory) {
// Convert the text files in a directory into an SFM book file
processDirectory(options.directory);
Expand All @@ -127,7 +136,7 @@ if (options.json) {
processBackSuperDirectory(options.backSuperDirectory).then(script1 => {
// Extra write of SFM Console log to extra book file after all the async processing finished
s.writeLog();
});
});
} else if (options.superDirectory) {
// Make all book folders from a super folder into SFM book files
processSuperDirectory(options.superDirectory);
Expand All @@ -152,7 +161,7 @@ async function processBackSuperDirectory(backSuperDirectory: string){
fileAssistant.getBookDirectories(backSuperDirectory, bookDirectories);
for(let i=0; i<bookDirectories.length; i++) {
await processBackDirectory(bookDirectories[i]);
};
}
}

/**
Expand All @@ -178,7 +187,7 @@ async function processBackDirectory(directory: string){
fileAssistant.getTextFilesInside(directory, filesToParse);
for (let i=0; i<filesToParse.length; i++) {
bookObj = await processBackText(filesToParse[i], bookObj);
};
}

// Directory processed, so write valid output
if (bookObj.header.bookInfo.code !== "000") {
Expand Down Expand Up @@ -239,14 +248,14 @@ async function processBackText(filepath: string, bookObj: books.objType): Promis
}

if (!bookObj.content[currentChapter]) {
console.error(`${bookInfo.bookName} has insufficent chapters allocated to handle ${currentChapter}. Exiting`);
console.error(`${bookInfo.bookName} has insufficient chapters allocated to handle ${currentChapter}. Exiting`);
process.exit(1);
}
if (bookObj.content[currentChapter].type != "chapter") {
// Initialize current chapter
bookObj.content[currentChapter].type = "chapter";
bookObj.content[currentChapter].content = [];
}
}

await backTranslation.updateObj(bookObj, filepath, currentChapter, s, debugMode);

Expand Down Expand Up @@ -288,7 +297,7 @@ function processText(filepath: string, bookObj: books.objType): books.objType {
}

if (!bookObj.content[currentChapter]) {
console.error(`${bookInfo.bookName} has insufficent chapters allocated to handle ${currentChapter}. Exiting`);
console.error(`${bookInfo.bookName} has insufficient chapters allocated to handle ${currentChapter}. Exiting`);
process.exit(1);
}
if (bookObj.content[currentChapter].type != "chapter") {
Expand Down Expand Up @@ -316,10 +325,12 @@ function processText(filepath: string, bookObj: books.objType): books.objType {
* Take a JSON file and make an SFM file
* @param {string} filepath - file path of a single JSON file
*/
function processJSON(filepath: string){
async function processJSON(filepath: string){
let bookObj: books.objType = books.PLACEHOLDER_BOOK_OBJ;
try {
console.log(`cwd: ${process.cwd()}`);
bookObj = require(filepath);
//bookObj = await import(filepath, {assert: {type: "json"}});
} catch (e) {
console.error("Invalid JSON file. Exiting")
process.exit(1);
Expand Down
6 changes: 3 additions & 3 deletions src/sfm.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2022 SIL International
// Utilities for converting a JSON file to USFM
import * as books from './books';
import * as sfmConsole from './sfmConsole';
import * as books from './books.js';
import * as sfmConsole from './sfmConsole.js';
import * as fs from 'fs';

/**
Expand Down Expand Up @@ -39,7 +39,7 @@ export function convertToSFM(bookObj: books.objType, s: sfmConsole.SFMConsole)
// For Chapter 1, marker must be followed by paragraph marker for styling in Paratext
SFMtext += PARAGRAPH_MARKER + CRLF;
} else {
// For other chapters, also insert pargraph marker if there's no section header before verse 1
// For other chapters, also insert paragraph marker if there's no section header before verse 1
if (chapter?.content && chapter.content[0].type != "section") {
SFMtext += PARAGRAPH_MARKER + CRLF;
}
Expand Down
8 changes: 4 additions & 4 deletions src/sfmConsole.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Copyright 2023 SIL International
// Utility to write to console along with "Extra Book A" SFM file.
import * as books from './books';
import * as books from './books.js';
import * as fs from 'fs';

/**
* Console level
*/
export type consoleType =
export type consoleType =
"warn" | "info" | "log" | "error";

export type consoleUnitType = {
Expand Down Expand Up @@ -49,7 +49,7 @@ export class SFMConsole {
console.error(text);
break;
default:
console.error(`SFMConsole(): Unxepected write mode: ${mode}\n`);
console.error(`SFMConsole(): Unexpected write mode: ${mode}\n`);
}

const unit: consoleUnitType = {
Expand All @@ -72,7 +72,7 @@ export class SFMConsole {
if (fs.existsSync(LOGFILE)) {
console.warn("Overwriting log file: " + LOGFILE);
}

const HEADER = '\\id ' + this.extraBook.code + ' - ' + this.projectName + '\n';
let content = HEADER;
this.loggingObj.forEach(l => {
Expand Down
6 changes: 3 additions & 3 deletions src/toolbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// Types and utilities for handling Toolbox text file
import * as fs from 'fs';
import * as path from 'path'
import * as books from './books';
import * as sfmConsole from './sfmConsole';
import * as books from './books.js';
import * as sfmConsole from './sfmConsole.js';

/**
* Enum to know what mode to parse the Toolbox file
Expand Down Expand Up @@ -86,7 +86,7 @@ export interface fileInfoType {
* @param {number} verseNum - current verse number
*/
export function getVerseBridge(line: string, verseNum: number) : bridgeType {
let bridge: bridgeType = {
const bridge: bridgeType = {
start: verseNum,
end: verseNum
};
Expand Down
8 changes: 4 additions & 4 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
"target": "ES2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "ESNext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
//"lib": ["es6", "es2015", "dom"], /* Specify library files to be included in the compilation. */
//"allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
Expand Down Expand Up @@ -41,7 +41,7 @@
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */

/* Module Resolution Options */
//"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
Expand All @@ -51,7 +51,7 @@
], /* List of folders to include type definitions from. */
//"types": ["node"], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
//"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"resolveJsonModule": true,
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
Expand Down