(core) Speed up and upgrade build.

Summary:
- Upgrades to build-related packages:
  - Upgrade typescript, related libraries and typings.
  - Upgrade webpack, eslint; add tsc-watch, node-dev, eslint_d.

- Build organization changes:
  - Build webpack from original typescript, transpiling only; with errors still
    reported by a background tsc watching process.

- Typescript-related changes:
  - Reduce imports of AWS dependencies (very noticeable speedup)
  - Avoid auto-loading global @types
  - Client code is now built with isolatedModules flag (for safe transpilation)
  - Use allowJs to avoid copying JS files manually.

- Linting changes
  - Enhance Arcanist ESLintLinter to run before/after commands, and set up to use eslint_d
  - Update eslint config, and include .eslintignore to avoid linting generated files.
  - Include a bunch of eslint-prompted and eslint-generated fixes
  - Add no-unused-expression rule to eslint, and fix a few warnings about it

- Other items:
  - Refactor cssInput to avoid circular dependency
  - Remove a bit of unused code, libraries, dependencies

Test Plan: No behavior changes, all existing tests pass. There are 30 tests fewer reported because `test_gpath.py` was removed (it's been unused for years)

Reviewers: paulfitz

Reviewed By: paulfitz

Subscribers: paulfitz

Differential Revision: https://phab.getgrist.com/D3498
This commit is contained in:
Dmitry S
2022-06-27 16:09:41 -04:00
parent 64ff9ccd0a
commit dd2eadc86e
45 changed files with 948 additions and 2442 deletions

View File

@@ -1,144 +0,0 @@
from six.moves import xrange
def _is_array(obj):
return isinstance(obj, list)
def get(obj, path):
"""
Looks up and returns a path in the object. Returns None if the path isn't there.
"""
for part in path:
try:
obj = obj[part]
except(KeyError, IndexError):
return None
return obj
def glob(obj, path, func, extra_arg):
"""
Resolves wildcards in `path`, calling func for all matching paths. Returns the number of
times that func was called.
obj - An object to scan.
path - Path to an item in an object or an array in obj. May contain the special key '*', which
-- for arrays only -- means "for all indices".
func - Will be called as func(subobj, key, fullPath, extraArg).
extra_arg - An arbitrary value to pass along to func, for convenience.
Returns count of matching paths, for which func got called.
"""
return _globHelper(obj, path, path, func, extra_arg)
def _globHelper(obj, path, full_path, func, extra_arg):
for i, part in enumerate(path[:-1]):
if part == "*" and _is_array(obj):
# We got an array wildcard
subpath = path[i + 1:]
count = 0
for subobj in obj:
count += _globHelper(subobj, subpath, full_path, func, extra_arg)
return count
try:
obj = obj[part]
except:
raise Exception("gpath.glob: non-existent object at " +
describe(full_path[:len(full_path) - len(path) + i + 1]))
return func(obj, path[-1], full_path, extra_arg) or 1
def place(obj, path, value):
"""
Sets or deletes an object property in DocObj.
gpath - Path to an Object in obj.
value - Any value. Setting None will remove the selected object key.
"""
return glob(obj, path, _placeHelper, value)
def _placeHelper(subobj, key, full_path, value):
if not isinstance(subobj, dict):
raise Exception("gpath.place: not a plain object at " + describe(dirname(full_path)))
if value is not None:
subobj[key] = value
elif key in subobj:
del subobj[key]
def _checkIsArray(subobj, errPrefix, index, itemPath, isInsert):
"""
This is a helper for checking operations on arrays, and throwing descriptive errors.
"""
if subobj is None:
raise Exception(errPrefix + ": non-existent object at " + describe(dirname(itemPath)))
elif not _is_array(subobj):
raise Exception(errPrefix + ": not an array at " + describe(dirname(itemPath)))
else:
length = len(subobj)
validIndex = (isinstance(index, int) and index >= 0 and index < length)
validInsertIndex = (index is None or index == length)
if not (validIndex or (isInsert and validInsertIndex)):
raise Exception(errPrefix + ": invalid array index: " + describe(itemPath))
def insert(obj, path, value):
"""
Inserts an element into an array in DocObj.
gpath - Path to an item in an array in obj.
The new value will be inserted before the item pointed to by gpath.
The last component of gpath may be null, in which case the value is appended at the end.
value - Any value.
"""
return glob(obj, path, _insertHelper, value)
def _insertHelper(subobj, index, fullPath, value):
_checkIsArray(subobj, "gpath.insert", index, fullPath, True)
if index is None:
subobj.append(value)
else:
subobj.insert(index, value)
def update(obj, path, value):
"""
Updates an element in an array in DocObj.
gpath - Path to an item in an array in obj.
value - Any value.
"""
return glob(obj, path, _updateHelper, value)
def _updateHelper(subobj, index, fullPath, value):
if index == '*':
_checkIsArray(subobj, "gpath.update", None, fullPath, True)
for i in xrange(len(subobj)):
subobj[i] = value
return len(subobj)
else:
_checkIsArray(subobj, "gpath.update", index, fullPath, False)
subobj[index] = value
def remove(obj, path):
"""
Removes an element from an array in DocObj.
gpath - Path to an item in an array in obj.
"""
return glob(obj, path, _removeHelper, None)
def _removeHelper(subobj, index, fullPath, _):
_checkIsArray(subobj, "gpath.remove", index, fullPath, False)
del subobj[index]
def dirname(path):
"""
Returns path without the last component, like a directory name in a filesystem path.
"""
return path[:-1]
def basename(path):
"""
Returns the last component of path, like base name of a filesystem path.
"""
return path[-1] if path else None
def describe(path):
"""
Returns a human-readable representation of path.
"""
return "/" + "/".join(str(p) for p in path)

View File

@@ -1,159 +0,0 @@
import unittest
import gpath
class TestGpath(unittest.TestCase):
def setUp(self):
self.obj = {
"foo": [{"bar": 1}, {"bar": 2}, {"baz": 3}],
"hello": "world"
}
def test_get(self):
self.assertEqual(gpath.get(self.obj, ["foo", 0, "bar"]), 1)
self.assertEqual(gpath.get(self.obj, ["foo", 2]), {"baz": 3})
self.assertEqual(gpath.get(self.obj, ["hello"]), "world")
self.assertEqual(gpath.get(self.obj, []), self.obj)
self.assertEqual(gpath.get(self.obj, ["foo", 0, "baz"]), None)
self.assertEqual(gpath.get(self.obj, ["foo", 4]), None)
self.assertEqual(gpath.get(self.obj, ["foo", 4, "baz"]), None)
self.assertEqual(gpath.get(self.obj, [0]), None)
def test_set(self):
gpath.place(self.obj, ["foo"], {"bar": 1, "baz": 2})
self.assertEqual(self.obj["foo"], {"bar": 1, "baz": 2})
gpath.place(self.obj, ["foo", "bar"], 17)
self.assertEqual(self.obj["foo"], {"bar": 17, "baz": 2})
gpath.place(self.obj, ["foo", "baz"], None)
self.assertEqual(self.obj["foo"], {"bar": 17})
self.assertEqual(self.obj["hello"], "world")
gpath.place(self.obj, ["hello"], None)
self.assertFalse("hello" in self.obj)
gpath.place(self.obj, ["hello"], None) # OK to remove a non-existent property.
self.assertFalse("hello" in self.obj)
gpath.place(self.obj, ["hello"], "blah")
self.assertEqual(self.obj["hello"], "blah")
def test_set_strict(self):
with self.assertRaisesRegex(Exception, r"non-existent"):
gpath.place(self.obj, ["bar", 4], 17)
with self.assertRaisesRegex(Exception, r"not a plain object"):
gpath.place(self.obj, ["foo", 0], 17)
def test_insert(self):
self.assertEqual(self.obj["foo"], [{"bar": 1}, {"bar": 2}, {"baz": 3}])
gpath.insert(self.obj, ["foo", 0], "asdf")
self.assertEqual(self.obj["foo"], ["asdf", {"bar": 1}, {"bar": 2}, {"baz": 3}])
gpath.insert(self.obj, ["foo", 3], "hello")
self.assertEqual(self.obj["foo"], ["asdf", {"bar": 1}, {"bar": 2}, "hello", {"baz": 3}])
gpath.insert(self.obj, ["foo", None], "world")
self.assertEqual(self.obj["foo"],
["asdf", {"bar": 1}, {"bar": 2}, "hello", {"baz": 3}, "world"])
def test_insert_strict(self):
with self.assertRaisesRegex(Exception, r'not an array'):
gpath.insert(self.obj, ["foo"], "asdf")
with self.assertRaisesRegex(Exception, r'invalid.*index'):
gpath.insert(self.obj, ["foo", -1], 17)
with self.assertRaisesRegex(Exception, r'invalid.*index'):
gpath.insert(self.obj, ["foo", "foo"], 17)
def test_update(self):
"""update should update array items"""
self.assertEqual(self.obj["foo"], [{"bar": 1}, {"bar": 2}, {"baz": 3}])
gpath.update(self.obj, ["foo", 0], "asdf")
self.assertEqual(self.obj["foo"], ["asdf", {"bar": 2}, {"baz": 3}])
gpath.update(self.obj, ["foo", 2], "hello")
self.assertEqual(self.obj["foo"], ["asdf", {"bar": 2}, "hello"])
gpath.update(self.obj, ["foo", 1], None)
self.assertEqual(self.obj["foo"], ["asdf", None, "hello"])
def test_update_strict(self):
"""update should be strict"""
with self.assertRaisesRegex(Exception, r'non-existent'):
gpath.update(self.obj, ["bar", 4], 17)
with self.assertRaisesRegex(Exception, r'not an array'):
gpath.update(self.obj, ["foo"], 17)
with self.assertRaisesRegex(Exception, r'invalid.*index'):
gpath.update(self.obj, ["foo", -1], 17)
with self.assertRaisesRegex(Exception, r'invalid.*index'):
gpath.update(self.obj, ["foo", None], 17)
def test_remove(self):
"""remove should remove indices"""
self.assertEqual(self.obj["foo"], [{"bar": 1}, {"bar": 2}, {"baz": 3}])
gpath.remove(self.obj, ["foo", 0])
self.assertEqual(self.obj["foo"], [{"bar": 2}, {"baz": 3}])
gpath.remove(self.obj, ["foo", 1])
self.assertEqual(self.obj["foo"], [{"bar": 2}])
gpath.remove(self.obj, ["foo", 0])
self.assertEqual(self.obj["foo"], [])
def test_remove_strict(self):
"""remove should be strict"""
with self.assertRaisesRegex(Exception, r'non-existent'):
gpath.remove(self.obj, ["bar", 4])
with self.assertRaisesRegex(Exception, r'not an array'):
gpath.remove(self.obj, ["foo"])
with self.assertRaisesRegex(Exception, r'invalid.*index'):
gpath.remove(self.obj, ["foo", -1])
with self.assertRaisesRegex(Exception, r'invalid.*index'):
gpath.remove(self.obj, ["foo", None])
def test_glob(self):
"""glob should scan arrays"""
self.assertEqual(self.obj["foo"], [{"bar": 1}, {"bar": 2}, {"baz": 3}])
self.assertEqual(gpath.place(self.obj, ["foo", "*", "bar"], 17), 3)
self.assertEqual(self.obj["foo"], [{"bar": 17}, {"bar": 17}, {"baz": 3, "bar": 17}])
with self.assertRaisesRegex(Exception, r'non-existent object at \/foo\/\*\/bad'):
gpath.place(self.obj, ["foo", "*", "bad", "test"], 10)
self.assertEqual(gpath.update(self.obj, ["foo", "*"], "hello"), 3)
self.assertEqual(self.obj["foo"], ["hello", "hello", "hello"])
def test_glob_strict_wildcard(self):
"""should only support tail wildcard for updates"""
with self.assertRaisesRegex(Exception, r'invalid array index'):
gpath.remove(self.obj, ["foo", "*"])
with self.assertRaisesRegex(Exception, r'invalid array index'):
gpath.insert(self.obj, ["foo", "*"], 1)
def test_glob_wildcard_keys(self):
"""should not scan object keys"""
self.assertEqual(self.obj["foo"], [{"bar": 1}, {"bar": 2}, {"baz": 3}])
self.assertEqual(gpath.place(self.obj, ["foo", 0, "*"], 17), 1)
self.assertEqual(self.obj["foo"], [{"bar": 1, '*': 17}, {"bar": 2}, {"baz": 3}])
with self.assertRaisesRegex(Exception, r'non-existent'):
gpath.place(self.obj, ["*", 0, "bar"], 17)
def test_glob_nested(self):
"""should scan nested arrays"""
self.obj = [{"a": [1,2,3]}, {"a": [4,5,6]}, {"a": [7,8,9]}]
self.assertEqual(gpath.update(self.obj, ["*", "a", "*"], 5), 9)
self.assertEqual(self.obj, [{"a": [5,5,5]}, {"a": [5,5,5]}, {"a": [5,5,5]}])
def test_dirname(self):
"""dirname should return path without last component"""
self.assertEqual(gpath.dirname(["foo", "bar", "baz"]), ["foo", "bar"])
self.assertEqual(gpath.dirname([1, 2]), [1])
self.assertEqual(gpath.dirname(["foo"]), [])
self.assertEqual(gpath.dirname([]), [])
def test_basename(self):
"""basename should return the last component of path"""
self.assertEqual(gpath.basename(["foo", "bar", "baz"]), "baz")
self.assertEqual(gpath.basename([1, 2]), 2)
self.assertEqual(gpath.basename(["foo"]), "foo")
self.assertEqual(gpath.basename([]), None)
if __name__ == "__main__":
unittest.main()