Coverage for gws-app/gws/spec/generator/main.py: 77%

100 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-10-16 23:09 +0200

1import os 

2 

3from .. import core 

4from . import base, configref, manifest, normalizer, parser, extractor, strings, typescript, util 

5 

6Error = base.Error 

7 

8 

9def generate_and_write(root_dir='', out_dir='', manifest_path='', debug=False): 

10 base.log.set_level('DEBUG' if debug else 'INFO') 

11 

12 gen = _run_generator(root_dir, out_dir, manifest_path, debug) 

13 

14 to_path(gen.specData, out_dir + '/specs.json') 

15 

16 util.write_file(gen.outDir + '/gws.generated.ts', gen.typescript) 

17 

18 util.write_file(gen.outDir + '/configref.en.md', gen.configRef['en']) 

19 util.write_file(gen.outDir + '/configref.de.md', gen.configRef['de']) 

20 

21 

22def generate(manifest_path='') -> core.SpecData: 

23 gen = _run_generator(manifest_path=manifest_path) 

24 return gen.specData 

25 

26 

27def to_path(specs: core.SpecData, path: str): 

28 util.write_json( 

29 path, 

30 { 

31 'meta': specs.meta, 

32 'chunks': specs.chunks, 

33 'serverTypes': specs.serverTypes, 

34 'strings': specs.strings, 

35 }, 

36 ) 

37 return path 

38 

39 

40def from_path(path: str) -> core.SpecData: 

41 d = util.read_json(path) 

42 s = core.SpecData() 

43 s.meta = d['meta'] 

44 s.chunks = [core.Chunk(**c) for c in d['chunks']] 

45 s.serverTypes = [core.make_type(t) for t in d['serverTypes']] 

46 s.strings = d['strings'] 

47 return s 

48 

49 

50def _run_generator(root_dir='', out_dir='', manifest_path='', debug=False): 

51 gen = base.Generator() 

52 gen.rootDir = root_dir or base.v.APP_DIR 

53 gen.outDir = out_dir 

54 gen.selfDir = base.v.SELF_DIR 

55 gen.debug = debug 

56 gen.manifestPath = manifest_path 

57 

58 _init_generator(gen) 

59 gen.dump('000_init') 

60 

61 parser.parse(gen) 

62 gen.dump('001_parsed') 

63 

64 normalizer.normalize(gen) 

65 gen.dump('002_normalized') 

66 

67 extractor.extract(gen) 

68 gen.dump('003_extracted') 

69 

70 gen.typescript = typescript.create(gen) 

71 gen.strings = strings.collect(gen) 

72 

73 gen.configRef['en'] = configref.create(gen, 'en') 

74 gen.configRef['de'] = configref.create(gen, 'de') 

75 

76 gen.specData = core.SpecData() 

77 gen.specData.meta = gen.meta 

78 gen.specData.chunks = gen.chunks 

79 gen.specData.serverTypes = gen.serverTypes 

80 gen.specData.strings = gen.strings 

81 

82 return gen 

83 

84 

85def _init_generator(gen: base.Generator): 

86 gen.meta = { 

87 'version': util.read_file(gen.rootDir + '/VERSION').strip(), 

88 'manifestPath': None, 

89 'manifest': None, 

90 } 

91 

92 def _chunk(name, source_dir, bundle_dir): 

93 cc = core.Chunk() 

94 cc.name = name 

95 cc.sourceDir = source_dir 

96 cc.bundleDir = bundle_dir 

97 cc.paths = {kind: [] for _, kind in base.v.FILE_KINDS} 

98 cc.exclude = [] 

99 return cc 

100 

101 gen.chunks = [] 

102 

103 for name, path in base.v.SYSTEM_CHUNKS: 

104 cc = _chunk( 

105 name, 

106 gen.rootDir + path, 

107 base.v.APP_DIR, 

108 ) 

109 gen.chunks.append(cc) 

110 

111 manifest_plugins = None 

112 

113 if gen.manifestPath: 

114 try: 

115 base.log.debug(f'loading manifest {gen.manifestPath!r}') 

116 gen.meta['manifestPath'] = gen.manifestPath 

117 gen.meta['manifest'] = manifest.from_path(gen.manifestPath) 

118 except Exception as exc: 

119 raise base.GeneratorError(f'error loading manifest {gen.manifestPath!r}') from exc 

120 manifest_plugins = gen.meta['manifest'].get('plugins') 

121 

122 plugin_dict = {} 

123 

124 # our plugins 

125 for path in util.find_dirs(gen.rootDir + base.v.PLUGIN_DIR): 

126 name = os.path.basename(path) 

127 cc = _chunk( 

128 base.v.PLUGIN_PREFIX + '.' + name, 

129 path, 

130 path, 

131 ) 

132 plugin_dict[cc.name] = cc 

133 

134 # manifest plugins 

135 for p in manifest_plugins or []: 

136 path = p.get('path') 

137 name = p.get('name') or os.path.basename(path) 

138 if not os.path.isdir(path): 

139 raise base.GeneratorError(f'error loading plugin {name!r}: directory {path!r} not found') 

140 cc = _chunk( 

141 base.v.PLUGIN_PREFIX + '.' + name, 

142 path, 

143 path, 

144 ) 

145 plugin_dict[cc.name] = cc 

146 

147 gen.chunks.extend(plugin_dict.values()) 

148 

149 for chunk in gen.chunks: 

150 if not os.path.isdir(chunk.sourceDir): 

151 continue 

152 

153 excl = base.v.EXCLUDE_PATHS + (chunk.exclude or []) 

154 

155 for path in util.find_files(chunk.sourceDir): 

156 if any(x in path for x in excl): 

157 continue 

158 for pattern, kind in base.v.FILE_KINDS: 

159 if path.endswith(pattern): 

160 chunk.paths[kind].append(path) 

161 break 

162 

163 root_cc = _chunk( 

164 'gws', 

165 gen.rootDir + '/gws', 

166 gen.rootDir + '/gws', 

167 ) 

168 root_cc.paths['python'] = [gen.rootDir + '/gws/__init__.py'] 

169 gen.chunks.insert(0, root_cc)