[ADD] cli: add a command to generate tsconfig

With the new native JS module system, we have a lot of new features for
the developer: autocompletion, docstrings, ...

However, it does not work across modules: if a JS file in
/addons/stock/static/src/some_file.js want to import a file in web, say
/addons/web/static/src/blabla.js, we will need to use a statement like
this:

import { something } from '@web/blabla';

Obviously, there is no automatic way for IDEs to know that '@web' should
map to 'addons/web'.

This is why we propose to use a tsconfig.json that defines the mapping
between modules and their paths.  This is not mandatory, and only
affects those developers that work commonly in JS.

Part of PR 63177

Co-authored-by: Francois (fge) <fge@odoo.com>
This commit is contained in:
Simon Genin (ges)
2021-02-15 10:18:11 +01:00
committed by Francois (fge)
co-authored by Francois
parent 8e29438d54
commit 396fec3929
4 changed files with 145 additions and 0 deletions
+1
View File
@@ -13,3 +13,4 @@ from . import server
from . import shell
from . import start
from . import populate
from . import tsconfig
+124
View File
@@ -0,0 +1,124 @@
import argparse
import glob
import json
import os
import re
import sys
from . import Command
from odoo.modules.module import MANIFEST_NAMES
class TSConfig(Command):
"""Generates tsconfig files for javascript code"""
def get_module_list(self, path):
return [
mod.split(os.path.sep)[-2]
for mname in MANIFEST_NAMES
for mod in glob.glob(os.path.join(path, f'*/{mname}'))
]
def clean_path(self, path):
return re.sub(r"/{2,}", "/", path)
def prefix_suffix_path(self, path, prefix, suffix):
return self.clean_path(f"{prefix}/{path}/{suffix}")
def remove_(self, modules, module):
for name, path in modules:
if module == name:
modules.remove((name, path))
def run(self, cmdargs):
parser = argparse.ArgumentParser(
prog="%s %s" % (sys.argv[0].split(os.path.sep)[-1], self.command_name),
description=self.__doc__
)
parser.add_argument('--addons-path', type=str, nargs=1, dest="paths")
args = parser.parse_args(args=cmdargs)
modules = {}
for path in args.paths[0].split(','):
for module in self.get_module_list(self.clean_path(path)):
modules[module] = self.prefix_suffix_path(module, path, "/static/src/*")
content = self.generate_file_content(modules)
# pylint: disable=bad-builtin
print(json.dumps(content, indent=2))
def generate_imports(self, modules):
return {
f'@{module}/*': [path]
for module, path in modules.items()
}
def generate_file_content(self, modules):
return {
'compilerOptions': {
"baseUrl": ".",
"checkJs": True,
"allowJs": True,
"noEmit": True,
"paths": self.generate_imports(modules)
}, "exclude": self.generate_excludes()
}
def generate_excludes(self):
return [
"/**/*.po",
"/**/*.py",
"/**/*.pyc",
"/**/*.xml",
"/**/*.png",
"/**/*.md",
"/**/*.dat",
"/**/*.scss",
"/**/*.jpg",
"/**/*.svg",
"/**/*.pot",
"/**/*.csv",
"/**/*.mo",
"/**/*.txt",
"/**/*.less",
"/**/*.bcmap",
"/**/*.properties",
"/**/*.html",
"/**/*.ttf",
"/**/*.rst",
"/**/*.css",
"/**/*.pack",
"/**/*.idx",
"/**/*.h",
"/**/*.map",
"/**/*.gif",
"/**/*.sample",
"/**/*.doctree",
"/**/*.so",
"/**/*.pdf",
"/**/*.xslt",
"/**/*.conf",
"/**/*.woff",
"/**/*.xsd",
"/**/*.eot",
"/**/*.jst",
"/**/*.flow",
"/**/*.sh",
"/**/*.yml",
"/**/*.pfb",
"/**/*.jpeg",
"/**/*.crt",
"/**/*.template",
"/**/*.pxd",
"/**/*.dylib",
"/**/*.pem",
"/**/*.rng",
"/**/*.xsl",
"/**/*.xls",
"/**/*.cfg",
"/**/*.pyi",
"/**/*.pth",
"/**/*.markdown",
"/**/*.key",
"/**/*.ico",
]