mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(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:
@@ -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)
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user