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

TypeScript rewrite #591

Draft
wants to merge 47 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
3157696
First steps towards TypeScript conversion
ExplodingCabbage Feb 28, 2025
0e25a14
Convert xml.js->xml.ts
ExplodingCabbage Mar 7, 2025
0262a2e
Add compilation to build step
ExplodingCabbage Mar 7, 2025
5aaa633
Rewrite base.js in TypeScript (maybe shit, need to review own work on…
ExplodingCabbage Mar 9, 2025
cfafa10
Rewrite json.js -> json.ts and get tests passing (I'm honestly shocke…
ExplodingCabbage Mar 10, 2025
2ac1627
array.js -> array.ts
ExplodingCabbage Mar 10, 2025
f4f7880
character.js -> character.ts
ExplodingCabbage Mar 10, 2025
2317d9c
css.js->css.ts
ExplodingCabbage Mar 10, 2025
4bd69ee
sentence.js->sentence.ts
ExplodingCabbage Mar 10, 2025
9b4fc4f
word.js -> word.ts
ExplodingCabbage Mar 10, 2025
cb03e0a
line.js -> line.ts
ExplodingCabbage Mar 10, 2025
90cbe7b
index.js->index.ts
ExplodingCabbage Mar 10, 2025
56cce5c
Convert a couple more fiiles
ExplodingCabbage Mar 10, 2025
143706b
Convert params.ts
ExplodingCabbage Mar 10, 2025
4cb52b4
string.js -> string.ts
ExplodingCabbage Mar 10, 2025
5ad83c6
Partly convert patch-related files to TypeScript; more to do
ExplodingCabbage Mar 10, 2025
2dd993e
Type more stuff
ExplodingCabbage Mar 11, 2025
88838c9
Begin converting line-endings.js. Interesting TypeScript bug along th…
ExplodingCabbage Mar 11, 2025
7e0d68b
Bump TypeScript
ExplodingCabbage Mar 11, 2025
bbe9520
Add link to bug report
ExplodingCabbage Mar 11, 2025
a21648e
Finish converted line-endings.js to TypeScript
ExplodingCabbage Mar 12, 2025
4b3691a
Add missing overloads to support case where argument type isn't known…
ExplodingCabbage Mar 12, 2025
88a5513
reverse.js -> reverse.ts
ExplodingCabbage Mar 12, 2025
72bc4dc
add todo
ExplodingCabbage Mar 12, 2025
c62827e
Rewrite base.ts types (breaks everything for now)
ExplodingCabbage Mar 12, 2025
be36cc0
Per-diff-function options types. Still not compiling but close.
ExplodingCabbage Mar 12, 2025
268e96b
Fix build
ExplodingCabbage Mar 14, 2025
0be74a5
Merge remote-tracking branch 'origin/master' into add-typescript
ExplodingCabbage Mar 14, 2025
f0cfaf6
Run 'yarn add @eslint/js typescript-eslint --save-dev' as suggested a…
ExplodingCabbage Mar 14, 2025
38faa69
Turn on recommended eslint rules as recommended by Getting Started gu…
ExplodingCabbage Mar 14, 2025
3de3195
Get linting of TypeScript working (now with the officially recommende…
ExplodingCabbage Mar 14, 2025
3714370
yarn lint --fix
ExplodingCabbage Mar 14, 2025
457e40a
Tweak some indentation that eslint broke
ExplodingCabbage Mar 14, 2025
2f07bc3
Fix a couple of linting errors
ExplodingCabbage Mar 14, 2025
9c865af
Allow explicit 'any'
ExplodingCabbage Mar 14, 2025
7a13d9f
Eliminate needless explicit respecification of rules that eslint.conf…
ExplodingCabbage Mar 14, 2025
1b6cf7e
Fix another eslint config bug
ExplodingCabbage Mar 14, 2025
4809714
Start using arrow functions and thereby resolve a https://typescript-…
ExplodingCabbage Mar 14, 2025
fa3cb01
Fix some linting errors about pointless escape sequences
ExplodingCabbage Mar 14, 2025
36580d0
Fix more linting errors about pointless escape sequences
ExplodingCabbage Mar 14, 2025
9f93ce0
Eliminate a util made redundant by Object.keys, and fix a linting err…
ExplodingCabbage Mar 14, 2025
91885c8
Fix a no-prototype-builtins linting error
ExplodingCabbage Mar 14, 2025
5e6adc7
Disable no-use-before-define for TypeScript code, where it's broken
ExplodingCabbage Mar 14, 2025
3fe6e57
Liberalise more rules
ExplodingCabbage Mar 14, 2025
ed5aaa0
Fix lint errors in parse.ts
ExplodingCabbage Mar 14, 2025
3a52b9e
Fix lint errors in apply.ts
ExplodingCabbage Mar 14, 2025
173bc03
Fix remaining linting errors
ExplodingCabbage Mar 14, 2025
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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ dist
yarn-error.log
.vscode
.nyc_output
/src/**/*.js
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@ For even more customisation of the diffing behavior, you can create a `new Diff.
* `tokenize(value, options)`: used to convert each of `oldString` and `newString` (after they've gone through `castInput`) to an array of tokens. Defaults to returning `value.split('')` (returning an array of individual characters).
* `removeEmpty(array)`: called on the arrays of tokens returned by `tokenize` and can be used to modify them. Defaults to stripping out falsey tokens, such as empty strings. `diffArrays` overrides this to simply return the `array`, which means that falsey values like empty strings can be handled like any other token by `diffArrays`.
* `equals(left, right, options)`: called to determine if two tokens (one from the old string, one from the new string) should be considered equal. Defaults to comparing them with `===`.
* `join(tokens)`: gets called with an array of consecutive tokens that have either all been added, all been removed, or are all common. Needs to join them into a single value that can be used as the `value` property of the [change object](#change-objects) for these tokens. Defaults to simply returning `tokens.join('')`.
* `postProcess(changeObjects)`: gets called at the end of the algorithm with the [change objects](#change-objects) produced, and can do final cleanups on them. Defaults to simply returning `changeObjects` unchanged.
* `join(tokens)`: gets called with an array of consecutive tokens that have either all been added, all been removed, or are all common. Needs to join them into a single value that can be used as the `value` property of the [change object](#change-objects) for these tokens. Defaults to simply returning `tokens.join('')` (and therefore by default will error out if your tokens are not strings; differs that support non-string tokens like `diffArrays` should override it to be a no-op to fix this).
* `postProcess(changeObjects, options)`: gets called at the end of the algorithm with the [change objects](#change-objects) produced, and can do final cleanups on them. Defaults to simply returning `changeObjects` unchanged.

### Change Objects
Many of the methods above return change objects. These objects consist of the following fields:
Expand Down
325 changes: 153 additions & 172 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,176 +1,157 @@
import globals from "globals";
import babelParser from "@babel/eslint-parser";

export default [
{
languageOptions: {
globals: {
...globals.browser,
},

parser: babelParser,
},

rules: {
// Possible Errors //
//-----------------//
"comma-dangle": [2, "never"],
"no-cond-assign": [2, "except-parens"],
"no-console": 1, // Allow for debugging
"no-constant-condition": 2,
"no-control-regex": 2,
"no-debugger": 1, // Allow for debugging
"no-dupe-args": 2,
"no-dupe-keys": 2,
"no-duplicate-case": 2,
"no-empty": 2,
"no-empty-character-class": 2,
"no-ex-assign": 2,
"no-extra-boolean-cast": 2,
"no-extra-parens": [2, "functions"],
"no-extra-semi": 2,
"no-func-assign": 2,
"no-invalid-regexp": 2,
"no-irregular-whitespace": 2,
"no-negated-in-lhs": 2,
"no-obj-calls": 2,
"no-regex-spaces": 2,
"no-unreachable": 1, // Optimizer and coverage will handle/highlight this and can be useful for debugging
"use-isnan": 2,
"valid-typeof": 2,

// Best Practices //
//----------------//
curly: 2,
"default-case": 1,

"dot-notation": [2, {
allowKeywords: false,
}],

"guard-for-in": 1,
"no-alert": 2,
"no-caller": 2,
"no-div-regex": 1,
"no-eval": 2,
"no-extend-native": 2,
"no-extra-bind": 2,
"no-fallthrough": 2,
"no-floating-decimal": 2,
"no-implied-eval": 2,
"no-iterator": 2,
"no-labels": 2,
"no-lone-blocks": 2,
"no-multi-spaces": 2,
"no-multi-str": 1,
"no-native-reassign": 2,
"no-new": 2,
"no-new-func": 2,
"no-new-wrappers": 2,
"no-octal": 2,
"no-octal-escape": 2,
"no-process-env": 2,
"no-proto": 2,
"no-redeclare": 2,
"no-return-assign": 2,
"no-script-url": 2,
"no-self-compare": 2,
"no-sequences": 2,
"no-throw-literal": 2,
"no-unused-expressions": 2,
"no-warning-comments": 1,
"no-with": 2,
radix: 2,
"wrap-iife": 2,

// Variables //
//-----------//
"no-catch-shadow": 2,
"no-delete-var": 2,
"no-label-var": 2,
"no-undef": 2,
"no-undef-init": 2,

"no-unused-vars": [2, {
vars: "all",
args: "after-used",
}],

"no-use-before-define": [2, "nofunc"],

// Node.js //
//---------//

// Stylistic //
//-----------//
"brace-style": [2, "1tbs", {
allowSingleLine: true,
}],
// @ts-check

camelcase: 2,

"comma-spacing": [2, {
before: false,
after: true,
}],

"comma-style": [2, "last"],
"consistent-this": [1, "self"],
"eol-last": 2,
"func-style": [2, "declaration"],

"key-spacing": [2, {
beforeColon: false,
afterColon: true,
}],

"new-cap": 2,
"new-parens": 2,
"no-array-constructor": 2,
"no-lonely-if": 2,
"no-mixed-spaces-and-tabs": 2,
"no-nested-ternary": 1,
"no-new-object": 2,
"no-spaced-func": 2,
"no-trailing-spaces": 2,

"quote-props": [2, "as-needed", {
keywords: true,
}],

quotes: [2, "single", "avoid-escape"],
semi: 2,

"semi-spacing": [2, {
before: false,
after: true,
}],

"space-before-blocks": [2, "always"],
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import globals from "globals";

"space-before-function-paren": [2, {
anonymous: "never",
named: "never",
}],
export default tseslint.config(
{
ignores: [
"**/*", // ignore everything...
"!src/**/", "!src/**/*.ts", // ... except our TypeScript source files...
"!test/**/", "!test/**/*.js", // ... and our tests
],
},
eslint.configs.recommended,
tseslint.configs.recommended,
{
languageOptions: {
globals: {
...globals.browser,
},
},

"space-in-parens": [2, "never"],
"space-infix-ops": 2,
"space-unary-ops": 2,
"spaced-comment": [2, "always"],
"wrap-regex": 1,
"no-var": 2,
},
rules: {
// Possible Errors //
//-----------------//
"comma-dangle": [2, "never"],
"no-console": 1, // Allow for debugging
"no-debugger": 1, // Allow for debugging
"no-extra-parens": [2, "functions"],
"no-extra-semi": 2,
"no-negated-in-lhs": 2,
"no-unreachable": 1, // Optimizer and coverage will handle/highlight this and can be useful for debugging

// Best Practices //
//----------------//
curly: 2,
"default-case": 1,
"dot-notation": [2, {
allowKeywords: false,
}],
"guard-for-in": 1,
"no-alert": 2,
"no-caller": 2,
"no-div-regex": 1,
"no-eval": 2,
"no-extend-native": 2,
"no-extra-bind": 2,
"no-floating-decimal": 2,
"no-implied-eval": 2,
"no-iterator": 2,
"no-labels": 2,
"no-lone-blocks": 2,
"no-multi-spaces": 2,
"no-multi-str": 1,
"no-native-reassign": 2,
"no-new": 2,
"no-new-func": 2,
"no-new-wrappers": 2,
"no-octal-escape": 2,
"no-process-env": 2,
"no-proto": 2,
"no-return-assign": 2,
"no-script-url": 2,
"no-self-compare": 2,
"no-sequences": 2,
"no-throw-literal": 2,
"no-unused-expressions": 2,
"no-warning-comments": 1,
radix: 2,
"wrap-iife": 2,

// Variables //
//-----------//
"no-catch-shadow": 2,
"no-label-var": 2,
"no-undef-init": 2,

// Node.js //
//---------//

// Stylistic //
//-----------//
"brace-style": [2, "1tbs", {
allowSingleLine: true,
}],
camelcase: 2,
"comma-spacing": [2, {
before: false,
after: true,
}],
"comma-style": [2, "last"],
"consistent-this": [1, "self"],
"eol-last": 2,
"func-style": [2, "declaration"],
"key-spacing": [2, {
beforeColon: false,
afterColon: true,
}],
"new-cap": 2,
"new-parens": 2,
"no-array-constructor": 2,
"no-lonely-if": 2,
"no-mixed-spaces-and-tabs": 2,
"no-nested-ternary": 1,
"no-new-object": 2,
"no-spaced-func": 2,
"no-trailing-spaces": 2,
"quote-props": [2, "as-needed", {
keywords: true,
}],
quotes: [2, "single", "avoid-escape"],
semi: 2,
"semi-spacing": [2, {
before: false,
after: true,
}],
"space-before-blocks": [2, "always"],
"space-before-function-paren": [2, {
anonymous: "never",
named: "never",
}],
"space-in-parens": [2, "never"],
"space-infix-ops": 2,
"space-unary-ops": 2,
"spaced-comment": [2, "always"],
"wrap-regex": 1,
"no-var": 2,

// Typescript //
//------------//
"@typescript-eslint/no-explicit-any": 0, // Very strict rule, incompatible with our code

// We use these intentionally - e.g.
// export interface DiffCssOptions extends CommonDiffOptions {}
// for the options argument to diffCss which currently takes no options beyond the ones
// common to all diffFoo functions. Doing this allows consistency (one options interface per
// diffFoo function) and future-proofs against the API having to change in future if we add a
// non-common option to one of these functions.
"@typescript-eslint/no-empty-object-type": [2, {allowInterfaces: 'with-single-extends'}],
},
},
{
files: ['test/**/*.js'],
languageOptions: {
globals: {
...globals.node,
...globals.mocha,
},
},
rules: {
"no-unused-expressions": 0, // Needs disabling to support Chai `.to.be.undefined` etc syntax
"@typescript-eslint/no-unused-expressions": 0, // (as above)
"no-use-before-define": [2, "nofunc"], // Useful rule but broken for TypeScript code
},
{
files: ['test/**/*.js'],
languageOptions: {
globals: {
...globals.node,
...globals.mocha,
},
},
rules: {
"no-unused-expressions": 0, // Needs disabling to support Chai `.to.be.undefined` etc syntax
},
}
];
}
);
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
},
"scripts": {
"clean": "rm -rf lib/ dist/ coverage/ .nyc_output/",
"lint": "yarn eslint 'src/**/*.js' 'test/**/*.js'",
"build": "yarn lint && yarn run-babel && yarn run-rollup && yarn run-uglify",
"lint": "yarn eslint",
"build": "yarn tsc src/*.ts src/**/*.ts --module es2015 --moduleResolution bundler --target es2022 && yarn run-babel && yarn run-rollup && yarn run-uglify",
"test": "nyc yarn _test",
"_test": "yarn build && cross-env NODE_ENV=test yarn run-mocha",
"run-babel": "babel --out-dir lib --source-maps=inline src",
Expand Down Expand Up @@ -74,12 +74,16 @@
"nyc": "^17.1.0",
"rollup": "^4.34.8",
"rollup-plugin-babel": "^4.4.0",
"typescript": "^5.7.3",
"uglify-js": "^3.19.3",
"webpack": "^5.98.0",
"webpack-dev-server": "^5.2.0"
},
"optionalDependencies": {},
"dependencies": {},
"dependencies": {
"@eslint/js": "^9.22.0",
"typescript-eslint": "^8.26.1"
},
"nyc": {
"require": [
"@babel/register"
Expand Down
10 changes: 7 additions & 3 deletions src/convert/dmp.js → src/convert/dmp.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import {ChangeObject} from '../types';

type DmpOperation = 1 | 0 | -1;

// See: http://code.google.com/p/google-diff-match-patch/wiki/API
export function convertChangesToDMP(changes) {
let ret = [],
change,
export function convertChangesToDMP<ValueT>(changes: ChangeObject<ValueT>[]): [DmpOperation, ValueT][] {
const ret = [];
let change,
operation;
for (let i = 0; i < changes.length; i++) {
change = changes[i];
Expand Down
Loading