@trebco/treb 23.6.5 → 25.0.0-rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +8 -0
- package/.eslintrc.js +164 -0
- package/README-shadow-DOM.md +88 -0
- package/README.md +37 -130
- package/api-config.json +29 -0
- package/api-generator/api-generator-types.ts +82 -0
- package/api-generator/api-generator.ts +1172 -0
- package/api-generator/package.json +3 -0
- package/build/treb-spreadsheet.mjs +14 -0
- package/{treb.d.ts → build/treb.d.ts} +323 -271
- package/esbuild-custom-element.mjs +336 -0
- package/esbuild.js +305 -0
- package/package.json +49 -14
- package/treb-base-types/package.json +5 -0
- package/treb-base-types/src/api_types.ts +36 -0
- package/treb-base-types/src/area.ts +583 -0
- package/treb-base-types/src/basic_types.ts +45 -0
- package/treb-base-types/src/cell.ts +612 -0
- package/treb-base-types/src/cells.ts +1066 -0
- package/treb-base-types/src/color.ts +124 -0
- package/treb-base-types/src/import.ts +71 -0
- package/treb-base-types/src/index-standalone.ts +29 -0
- package/treb-base-types/src/index.ts +42 -0
- package/treb-base-types/src/layout.ts +47 -0
- package/treb-base-types/src/localization.ts +187 -0
- package/treb-base-types/src/rectangle.ts +145 -0
- package/treb-base-types/src/render_text.ts +72 -0
- package/treb-base-types/src/style.ts +545 -0
- package/treb-base-types/src/table.ts +109 -0
- package/treb-base-types/src/text_part.ts +54 -0
- package/treb-base-types/src/theme.ts +608 -0
- package/treb-base-types/src/union.ts +152 -0
- package/treb-base-types/src/value-type.ts +164 -0
- package/treb-base-types/style/resizable.css +59 -0
- package/treb-calculator/modern.tsconfig.json +11 -0
- package/treb-calculator/package.json +5 -0
- package/treb-calculator/src/calculator.ts +2546 -0
- package/treb-calculator/src/complex-math.ts +558 -0
- package/treb-calculator/src/dag/array-vertex.ts +198 -0
- package/treb-calculator/src/dag/graph.ts +951 -0
- package/treb-calculator/src/dag/leaf_vertex.ts +118 -0
- package/treb-calculator/src/dag/spreadsheet_vertex.ts +327 -0
- package/treb-calculator/src/dag/spreadsheet_vertex_base.ts +44 -0
- package/treb-calculator/src/dag/vertex.ts +352 -0
- package/treb-calculator/src/descriptors.ts +162 -0
- package/treb-calculator/src/expression-calculator.ts +1069 -0
- package/treb-calculator/src/function-error.ts +103 -0
- package/treb-calculator/src/function-library.ts +103 -0
- package/treb-calculator/src/functions/base-functions.ts +1214 -0
- package/treb-calculator/src/functions/checkbox.ts +164 -0
- package/treb-calculator/src/functions/complex-functions.ts +253 -0
- package/treb-calculator/src/functions/finance-functions.ts +399 -0
- package/treb-calculator/src/functions/information-functions.ts +102 -0
- package/treb-calculator/src/functions/matrix-functions.ts +182 -0
- package/treb-calculator/src/functions/sparkline.ts +335 -0
- package/treb-calculator/src/functions/statistics-functions.ts +350 -0
- package/treb-calculator/src/functions/text-functions.ts +298 -0
- package/treb-calculator/src/index.ts +27 -0
- package/treb-calculator/src/notifier-types.ts +59 -0
- package/treb-calculator/src/primitives.ts +428 -0
- package/treb-calculator/src/utilities.ts +305 -0
- package/treb-charts/package.json +5 -0
- package/treb-charts/src/chart-functions.ts +156 -0
- package/treb-charts/src/chart-types.ts +230 -0
- package/treb-charts/src/chart.ts +1288 -0
- package/treb-charts/src/index.ts +24 -0
- package/treb-charts/src/main.ts +37 -0
- package/treb-charts/src/rectangle.ts +52 -0
- package/treb-charts/src/renderer.ts +1841 -0
- package/treb-charts/src/util.ts +122 -0
- package/treb-charts/style/charts.scss +221 -0
- package/treb-charts/style/old-charts.scss +250 -0
- package/treb-embed/markup/layout.html +137 -0
- package/treb-embed/markup/toolbar.html +175 -0
- package/treb-embed/modern.tsconfig.json +25 -0
- package/treb-embed/src/custom-element/content-types.d.ts +18 -0
- package/treb-embed/src/custom-element/global.d.ts +11 -0
- package/treb-embed/src/custom-element/spreadsheet-constructor.ts +1228 -0
- package/treb-embed/src/custom-element/treb-global.ts +44 -0
- package/treb-embed/src/custom-element/treb-spreadsheet-element.ts +52 -0
- package/treb-embed/src/embedded-spreadsheet.ts +5358 -0
- package/treb-embed/src/index.ts +16 -0
- package/treb-embed/src/language-model.ts +41 -0
- package/treb-embed/src/options.ts +298 -0
- package/treb-embed/src/progress-dialog.ts +228 -0
- package/treb-embed/src/selection-state.ts +16 -0
- package/treb-embed/src/spinner.ts +42 -0
- package/treb-embed/src/toolbar-message.ts +96 -0
- package/treb-embed/src/types.ts +167 -0
- package/treb-embed/style/autocomplete.scss +103 -0
- package/treb-embed/style/dark-theme.scss +114 -0
- package/treb-embed/style/defaults.scss +36 -0
- package/treb-embed/style/dialog.scss +181 -0
- package/treb-embed/style/dropdown-select.scss +101 -0
- package/treb-embed/style/formula-bar.scss +193 -0
- package/treb-embed/style/grid.scss +374 -0
- package/treb-embed/style/layout.scss +424 -0
- package/treb-embed/style/mouse-mask.scss +67 -0
- package/treb-embed/style/note.scss +92 -0
- package/treb-embed/style/overlay-editor.scss +102 -0
- package/treb-embed/style/spinner.scss +92 -0
- package/treb-embed/style/tab-bar.scss +228 -0
- package/treb-embed/style/table.scss +80 -0
- package/treb-embed/style/theme-defaults.scss +444 -0
- package/treb-embed/style/toolbar.scss +416 -0
- package/treb-embed/style/tooltip.scss +68 -0
- package/treb-embed/style/treb-icons.scss +130 -0
- package/treb-embed/style/treb-spreadsheet-element.scss +20 -0
- package/treb-embed/style/z-index.scss +43 -0
- package/treb-export/docs/charts.md +68 -0
- package/treb-export/modern.tsconfig.json +19 -0
- package/treb-export/package.json +4 -0
- package/treb-export/src/address-type.ts +77 -0
- package/treb-export/src/base-template.ts +22 -0
- package/treb-export/src/column-width.ts +85 -0
- package/treb-export/src/drawing2/chart-template-components2.ts +389 -0
- package/treb-export/src/drawing2/chart2.ts +282 -0
- package/treb-export/src/drawing2/column-chart-template2.ts +521 -0
- package/treb-export/src/drawing2/donut-chart-template2.ts +296 -0
- package/treb-export/src/drawing2/drawing2.ts +355 -0
- package/treb-export/src/drawing2/embedded-image.ts +71 -0
- package/treb-export/src/drawing2/scatter-chart-template2.ts +555 -0
- package/treb-export/src/export-worker/export-worker.ts +99 -0
- package/treb-export/src/export-worker/index-modern.ts +22 -0
- package/treb-export/src/export2.ts +2204 -0
- package/treb-export/src/import2.ts +882 -0
- package/treb-export/src/relationship.ts +36 -0
- package/treb-export/src/shared-strings2.ts +128 -0
- package/treb-export/src/template-2.ts +22 -0
- package/treb-export/src/unescape_xml.ts +47 -0
- package/treb-export/src/workbook-sheet2.ts +182 -0
- package/treb-export/src/workbook-style2.ts +1285 -0
- package/treb-export/src/workbook-theme2.ts +88 -0
- package/treb-export/src/workbook2.ts +491 -0
- package/treb-export/src/xml-utils.ts +201 -0
- package/treb-export/template/base/[Content_Types].xml +2 -0
- package/treb-export/template/base/_rels/.rels +2 -0
- package/treb-export/template/base/docProps/app.xml +2 -0
- package/treb-export/template/base/docProps/core.xml +12 -0
- package/treb-export/template/base/xl/_rels/workbook.xml.rels +2 -0
- package/treb-export/template/base/xl/sharedStrings.xml +2 -0
- package/treb-export/template/base/xl/styles.xml +2 -0
- package/treb-export/template/base/xl/theme/theme1.xml +2 -0
- package/treb-export/template/base/xl/workbook.xml +2 -0
- package/treb-export/template/base/xl/worksheets/sheet1.xml +2 -0
- package/treb-export/template/base.xlsx +0 -0
- package/treb-format/package.json +8 -0
- package/treb-format/src/format.test.ts +213 -0
- package/treb-format/src/format.ts +942 -0
- package/treb-format/src/format_cache.ts +199 -0
- package/treb-format/src/format_parser.ts +723 -0
- package/treb-format/src/index.ts +25 -0
- package/treb-format/src/number_format_section.ts +100 -0
- package/treb-format/src/value_parser.ts +337 -0
- package/treb-grid/package.json +5 -0
- package/treb-grid/src/editors/autocomplete.ts +394 -0
- package/treb-grid/src/editors/autocomplete_matcher.ts +260 -0
- package/treb-grid/src/editors/formula_bar.ts +473 -0
- package/treb-grid/src/editors/formula_editor_base.ts +910 -0
- package/treb-grid/src/editors/overlay_editor.ts +511 -0
- package/treb-grid/src/index.ts +37 -0
- package/treb-grid/src/layout/base_layout.ts +2618 -0
- package/treb-grid/src/layout/grid_layout.ts +299 -0
- package/treb-grid/src/layout/rectangle_cache.ts +86 -0
- package/treb-grid/src/render/selection-renderer.ts +414 -0
- package/treb-grid/src/render/svg_header_overlay.ts +93 -0
- package/treb-grid/src/render/svg_selection_block.ts +187 -0
- package/treb-grid/src/render/tile_renderer.ts +2122 -0
- package/treb-grid/src/types/annotation.ts +216 -0
- package/treb-grid/src/types/border_constants.ts +34 -0
- package/treb-grid/src/types/clipboard_data.ts +31 -0
- package/treb-grid/src/types/data_model.ts +334 -0
- package/treb-grid/src/types/drag_mask.ts +81 -0
- package/treb-grid/src/types/grid.ts +7743 -0
- package/treb-grid/src/types/grid_base.ts +3644 -0
- package/treb-grid/src/types/grid_command.ts +470 -0
- package/treb-grid/src/types/grid_events.ts +124 -0
- package/treb-grid/src/types/grid_options.ts +97 -0
- package/treb-grid/src/types/grid_selection.ts +60 -0
- package/treb-grid/src/types/named_range.ts +369 -0
- package/treb-grid/src/types/scale-control.ts +202 -0
- package/treb-grid/src/types/serialize_options.ts +72 -0
- package/treb-grid/src/types/set_range_options.ts +52 -0
- package/treb-grid/src/types/sheet.ts +3099 -0
- package/treb-grid/src/types/sheet_types.ts +95 -0
- package/treb-grid/src/types/tab_bar.ts +464 -0
- package/treb-grid/src/types/tile.ts +59 -0
- package/treb-grid/src/types/update_flags.ts +75 -0
- package/treb-grid/src/util/dom_utilities.ts +44 -0
- package/treb-grid/src/util/fontmetrics2.ts +179 -0
- package/treb-grid/src/util/ua.ts +104 -0
- package/treb-logo.svg +18 -0
- package/treb-parser/package.json +5 -0
- package/treb-parser/src/csv-parser.ts +122 -0
- package/treb-parser/src/index.ts +25 -0
- package/treb-parser/src/md-parser.ts +526 -0
- package/treb-parser/src/parser-types.ts +397 -0
- package/treb-parser/src/parser.test.ts +298 -0
- package/treb-parser/src/parser.ts +2673 -0
- package/treb-utils/package.json +5 -0
- package/treb-utils/src/dispatch.ts +57 -0
- package/treb-utils/src/event_source.ts +147 -0
- package/treb-utils/src/ievent_source.ts +33 -0
- package/treb-utils/src/index.ts +31 -0
- package/treb-utils/src/measurement.ts +174 -0
- package/treb-utils/src/resizable.ts +160 -0
- package/treb-utils/src/scale.ts +137 -0
- package/treb-utils/src/serialize_html.ts +124 -0
- package/treb-utils/src/template.ts +70 -0
- package/treb-utils/src/validate_uri.ts +61 -0
- package/tsconfig.json +10 -0
- package/tsproject.json +30 -0
- package/util/license-plugin-esbuild.js +86 -0
- package/util/list-css-vars.sh +46 -0
- package/README-esm.md +0 -37
- package/treb-bundle.css +0 -2
- package/treb-bundle.mjs +0 -15
|
@@ -0,0 +1,1172 @@
|
|
|
1
|
+
|
|
2
|
+
import * as ts from 'typescript';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
|
|
6
|
+
import type { Config, ReadTypeArgs } from './api-generator-types';
|
|
7
|
+
|
|
8
|
+
let config_file = './api-config.json';
|
|
9
|
+
for (let i = 0; i < process.argv.length; i++) {
|
|
10
|
+
if (process.argv[i] === '-c' || process.argv[i] === '--config') {
|
|
11
|
+
config_file = process.argv[++i];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// all files should be relative to the config file.
|
|
16
|
+
const config_dir = path.dirname(config_file);
|
|
17
|
+
|
|
18
|
+
let config: Config = {
|
|
19
|
+
root: '',
|
|
20
|
+
index: '',
|
|
21
|
+
package: '',
|
|
22
|
+
drop_types: [],
|
|
23
|
+
convert_to_any: [],
|
|
24
|
+
exclude_tags: [],
|
|
25
|
+
rename_types: {},
|
|
26
|
+
drop_generics: [],
|
|
27
|
+
map: {},
|
|
28
|
+
include: [],
|
|
29
|
+
flatten_enums: false,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
let api_version = '';
|
|
33
|
+
|
|
34
|
+
const ReadConfigData = async (file: string) => {
|
|
35
|
+
|
|
36
|
+
const text = await fs.promises.readFile(file, {encoding: 'utf8'});
|
|
37
|
+
const obj = JSON.parse(text);
|
|
38
|
+
config = {
|
|
39
|
+
...config,
|
|
40
|
+
...obj,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
if (config.package) {
|
|
44
|
+
const pkg = await fs.promises.readFile(path.join(config_dir, config.package), {encoding: 'utf8'});
|
|
45
|
+
const data = JSON.parse(pkg);
|
|
46
|
+
api_version = data.version.replace(/\.\d+$/, '');
|
|
47
|
+
console.info('v', api_version);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
///
|
|
53
|
+
|
|
54
|
+
const FlattenQualifiedName = (node: ts.QualifiedName): string[] => {
|
|
55
|
+
|
|
56
|
+
const stack: string[] = [];
|
|
57
|
+
|
|
58
|
+
if (ts.isIdentifier(node.left)) {
|
|
59
|
+
stack.push(node.left.escapedText.toString());
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
stack.push(...FlattenQualifiedName(node.left));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
stack.push(node.right.escapedText.toString());
|
|
66
|
+
|
|
67
|
+
return stack;
|
|
68
|
+
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/*
|
|
72
|
+
const FlattenEntityName = (name: ts.EntityName, base?: string): string => {
|
|
73
|
+
if (ts.isIdentifier(name)) {
|
|
74
|
+
return name.escapedText.toString() + (base ? '.' + base : '');
|
|
75
|
+
}
|
|
76
|
+
base = name.right.escapedText.toString() + (base ? '.' + base : '');
|
|
77
|
+
return FlattenEntityName(name.left, base);
|
|
78
|
+
};
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
const GetDocTags = (node: ts.Node): string[] => {
|
|
82
|
+
const tags = ts.getAllJSDocTags(node, (tag: ts.JSDocTag): tag is ts.JSDocTag => true);
|
|
83
|
+
return tags.map(tag => {
|
|
84
|
+
return tag.tagName.escapedText as string;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* when adding fake (synthetic) comments, the printer will add multiline
|
|
90
|
+
* comment markers \/* *\/. we need to remove them.
|
|
91
|
+
* @param text
|
|
92
|
+
*/
|
|
93
|
+
function CleanComment(text: string): string {
|
|
94
|
+
|
|
95
|
+
if (/^\/\*/.test(text)) {
|
|
96
|
+
text = text.substring(2);
|
|
97
|
+
}
|
|
98
|
+
if (/\*\/$/.test(text)) {
|
|
99
|
+
text = text.substring(0, text.length - 2);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return text;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
*
|
|
107
|
+
* @param args
|
|
108
|
+
* @returns
|
|
109
|
+
*/
|
|
110
|
+
function CleanTransformer<T extends ts.Node>(): ts.TransformerFactory<T> {
|
|
111
|
+
|
|
112
|
+
const rename_keys = Object.keys(config.rename_types);
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* flag indicates we're in an exported module. in this case, export is
|
|
116
|
+
* implicit so don't gate on that (otherwise we drop types that should be
|
|
117
|
+
* included).
|
|
118
|
+
*/
|
|
119
|
+
let exported_module = false;
|
|
120
|
+
|
|
121
|
+
return context => {
|
|
122
|
+
const visit: ts.Visitor = node => {
|
|
123
|
+
|
|
124
|
+
const modifiers = (node.modifiers || []).map(member => {
|
|
125
|
+
return ts.SyntaxKind[member.kind];
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const tags = GetDocTags(node);
|
|
129
|
+
const internal =
|
|
130
|
+
tags.some(test => config.exclude_tags.includes(test));
|
|
131
|
+
|
|
132
|
+
const exported = modifiers.includes('ExportKeyword');
|
|
133
|
+
const is_public = !(modifiers.includes('ProtectedKeyword') || modifiers.includes('PrivateKeyword'));
|
|
134
|
+
|
|
135
|
+
if (ts.isModuleDeclaration(node)
|
|
136
|
+
|| ts.isClassDeclaration(node)
|
|
137
|
+
|| ts.isInterfaceDeclaration(node)
|
|
138
|
+
|| ts.isTypeAliasDeclaration(node)
|
|
139
|
+
|| ts.isEnumDeclaration(node)) {
|
|
140
|
+
|
|
141
|
+
// FIXME: one of these declarations might be exported via
|
|
142
|
+
// its module, and not independently; in that case we might
|
|
143
|
+
// still need it.
|
|
144
|
+
|
|
145
|
+
if ((!exported && !exported_module) || internal) {
|
|
146
|
+
if (node.name && ts.isIdentifier(node.name)) {
|
|
147
|
+
// console.info('dropping', node.name.escapedText.toString());
|
|
148
|
+
}
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let name = '';
|
|
153
|
+
|
|
154
|
+
if (node.name && ts.isIdentifier(node.name)) {
|
|
155
|
+
name = node.name.escapedText.toString();
|
|
156
|
+
// console.info('keeping', node.name.escapedText.toString());
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (ts.isModuleDeclaration(node)) {
|
|
160
|
+
exported_module = true;
|
|
161
|
+
const result = ts.visitEachChild(node, child => visit(child), context);
|
|
162
|
+
exported_module = false;
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (ts.isClassDeclaration(node)) {
|
|
167
|
+
if (config.drop_generics.includes(name)) {
|
|
168
|
+
|
|
169
|
+
const tmp = ts.factory.updateClassDeclaration(node,
|
|
170
|
+
// node.decorators,
|
|
171
|
+
node.modifiers,
|
|
172
|
+
node.name,
|
|
173
|
+
[], // node.typeParameters,
|
|
174
|
+
node.heritageClauses,
|
|
175
|
+
node.members);
|
|
176
|
+
|
|
177
|
+
return ts.visitEachChild(tmp, child => visit(child), context);
|
|
178
|
+
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (ts.isEnumDeclaration(node)) {
|
|
183
|
+
if (config.flatten_enums) {
|
|
184
|
+
|
|
185
|
+
const alias = ts.factory.createTypeAliasDeclaration(
|
|
186
|
+
// node.decorators,
|
|
187
|
+
node.modifiers,
|
|
188
|
+
node.name,
|
|
189
|
+
[],
|
|
190
|
+
ts.factory.createUnionTypeNode(
|
|
191
|
+
node.members.map((member, i) => {
|
|
192
|
+
|
|
193
|
+
if (member.initializer) {
|
|
194
|
+
|
|
195
|
+
if (ts.isNumericLiteral(member.initializer)
|
|
196
|
+
|| ts.isStringLiteral(member.initializer)) {
|
|
197
|
+
return ts.factory.createLiteralTypeNode(member.initializer);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// this may be wrong if there are some initializers [FIXME].
|
|
202
|
+
// what happens if you say
|
|
203
|
+
//
|
|
204
|
+
// enum X = { A, B = 3, C }
|
|
205
|
+
//
|
|
206
|
+
// it's probably something like resetting the automatic counter,
|
|
207
|
+
// which we could do. need to investigate though.
|
|
208
|
+
|
|
209
|
+
return ts.factory.createLiteralTypeNode(ts.factory.createNumericLiteral(i));
|
|
210
|
+
|
|
211
|
+
})
|
|
212
|
+
));
|
|
213
|
+
|
|
214
|
+
if ((node as any).jsDoc) {
|
|
215
|
+
|
|
216
|
+
const source_text = node.getSourceFile().text;
|
|
217
|
+
const jsDoc: ts.JSDoc[] = (node as any).jsDoc;
|
|
218
|
+
const comment = CleanComment(source_text.substring(jsDoc[0].pos, jsDoc[0].end));
|
|
219
|
+
|
|
220
|
+
ts.addSyntheticLeadingComment(alias, ts.SyntaxKind.MultiLineCommentTrivia, comment);
|
|
221
|
+
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return ts.visitEachChild(alias, child => visit(child), context);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (ts.isInterfaceDeclaration(node)) {
|
|
230
|
+
|
|
231
|
+
// drop any internals
|
|
232
|
+
|
|
233
|
+
const tmp = ts.factory.updateInterfaceDeclaration(node,
|
|
234
|
+
// node.decorators,
|
|
235
|
+
node.modifiers,
|
|
236
|
+
node.name,
|
|
237
|
+
node.typeParameters,
|
|
238
|
+
node.heritageClauses,
|
|
239
|
+
node.members.filter(member => {
|
|
240
|
+
|
|
241
|
+
const member_tags = GetDocTags(member);
|
|
242
|
+
const internal = member_tags.some(test => config.exclude_tags.includes(test));
|
|
243
|
+
|
|
244
|
+
if (internal) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return true;
|
|
249
|
+
|
|
250
|
+
}));
|
|
251
|
+
|
|
252
|
+
return ts.visitEachChild(tmp, child => visit(child), context);
|
|
253
|
+
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (ts.isIdentifier(node)) {
|
|
259
|
+
const name = node.escapedText.toString();
|
|
260
|
+
if (rename_keys.includes(name)) {
|
|
261
|
+
// console.info( ' ** ', name);
|
|
262
|
+
return ts.factory.createIdentifier(config.rename_types[name]);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (ts.isMethodDeclaration(node)
|
|
267
|
+
|| ts.isConstructorDeclaration(node)
|
|
268
|
+
|| ts.isPropertyDeclaration(node)
|
|
269
|
+
|| ts.isAccessor(node)) {
|
|
270
|
+
|
|
271
|
+
if (internal || !is_public) {
|
|
272
|
+
return undefined;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// FIXME: fix ctor parameters like method parameters
|
|
276
|
+
|
|
277
|
+
if (ts.isMethodDeclaration(node)) {
|
|
278
|
+
|
|
279
|
+
// UPDATE: convert to any -> handle return type
|
|
280
|
+
|
|
281
|
+
let return_type = node.type;
|
|
282
|
+
if (return_type && ts.isTypeReferenceNode(return_type)) {
|
|
283
|
+
if (ts.isIdentifier(return_type.typeName)) {
|
|
284
|
+
const name = return_type.typeName.escapedText.toString();
|
|
285
|
+
if (config.convert_to_any.includes(name)) {
|
|
286
|
+
return_type = ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const tmp = ts.factory.updateMethodDeclaration(node,
|
|
292
|
+
// node.decorators,
|
|
293
|
+
node.modifiers,
|
|
294
|
+
node.asteriskToken,
|
|
295
|
+
node.name,
|
|
296
|
+
node.questionToken,
|
|
297
|
+
node.typeParameters,
|
|
298
|
+
node.parameters.filter((test, index) => {
|
|
299
|
+
if (test.type && ts.isTypeReferenceNode(test.type)) {
|
|
300
|
+
if (ts.isIdentifier(test.type.typeName)) {
|
|
301
|
+
const name = test.type.typeName.escapedText.toString();
|
|
302
|
+
if (config.drop_types.includes(name)) {
|
|
303
|
+
|
|
304
|
+
// we want to drop it. it must be optional and
|
|
305
|
+
// at the end... (of course that won't work if
|
|
306
|
+
// there are 2, but we don't have that problem atm).
|
|
307
|
+
|
|
308
|
+
// you could solve that by reversing the array, then
|
|
309
|
+
// you would only ever drop from the end. remember
|
|
310
|
+
// to reverse it again before returning.
|
|
311
|
+
|
|
312
|
+
if (test.questionToken && index === node.parameters.length - 1) {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return true;
|
|
320
|
+
}).map(test => {
|
|
321
|
+
if (test.type && ts.isTypeReferenceNode(test.type)) {
|
|
322
|
+
if (ts.isIdentifier(test.type.typeName)) {
|
|
323
|
+
const name = test.type.typeName.escapedText.toString();
|
|
324
|
+
if (config.convert_to_any.includes(name)) {
|
|
325
|
+
|
|
326
|
+
// convert this type to any
|
|
327
|
+
|
|
328
|
+
return ts.factory.createParameterDeclaration(
|
|
329
|
+
// test.decorators,
|
|
330
|
+
test.modifiers,
|
|
331
|
+
test.dotDotDotToken,
|
|
332
|
+
test.name,
|
|
333
|
+
test.questionToken,
|
|
334
|
+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
|
|
335
|
+
// test.type,
|
|
336
|
+
test.initializer
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return test;
|
|
343
|
+
}),
|
|
344
|
+
return_type, // node.type,
|
|
345
|
+
node.body);
|
|
346
|
+
|
|
347
|
+
return ts.visitEachChild(tmp, child => visit(child), context);
|
|
348
|
+
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (exported_module) {
|
|
353
|
+
if (ts.isVariableStatement(node)) {
|
|
354
|
+
|
|
355
|
+
const internal = tags.some(test => config.exclude_tags.includes(test));
|
|
356
|
+
|
|
357
|
+
if (internal || !is_public) {
|
|
358
|
+
return undefined;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return ts.visitEachChild(node, child => visit(child), context);
|
|
364
|
+
}
|
|
365
|
+
return node => ts.visitNode(node, visit);
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* collect all dependencies, recursively.
|
|
372
|
+
*
|
|
373
|
+
* FIXME: namespacing
|
|
374
|
+
* FIXME: collisions
|
|
375
|
+
*
|
|
376
|
+
*/
|
|
377
|
+
function CollectDependencyTransformer<T extends ts.Node>(
|
|
378
|
+
args: ReadTypeArgs): ts.TransformerFactory<T> {
|
|
379
|
+
|
|
380
|
+
const containing_type: string[] = [''];
|
|
381
|
+
|
|
382
|
+
const AddFoundType = (name: string, text: string): boolean => {
|
|
383
|
+
|
|
384
|
+
if (config.drop_types.includes(name) || config.convert_to_any.includes(name)) {
|
|
385
|
+
return false; // aggressive
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (!args.types) {
|
|
389
|
+
args.found_types[name] = text;
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
if (args.types.includes(name)) {
|
|
393
|
+
args.found_types[name] = text;
|
|
394
|
+
args.types = args.types.filter(test => test !== name);
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
args.extra_types[name] = text;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return true;
|
|
402
|
+
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
const AddReferencedType = (name: string, track: number) => {
|
|
406
|
+
|
|
407
|
+
// we're trying to block intrinsic types here but this will still
|
|
408
|
+
// miss DOM types since they're not present in node... either we
|
|
409
|
+
// need a more robust mechanism or we should just not bother.
|
|
410
|
+
|
|
411
|
+
const check = (global as any)[name];
|
|
412
|
+
if (check) {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (config.drop_types.includes(name) || config.convert_to_any.includes(name)) {
|
|
417
|
+
return false; // aggressive
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const container = containing_type[0];
|
|
421
|
+
|
|
422
|
+
const list = args.referenced_type_map[container] || [];
|
|
423
|
+
if (!list.includes(name)) {
|
|
424
|
+
list.push(name);
|
|
425
|
+
}
|
|
426
|
+
args.referenced_type_map[container] = list;
|
|
427
|
+
|
|
428
|
+
args.referenced_types[name] = (args.referenced_types[name]||0) + 1;
|
|
429
|
+
return true;
|
|
430
|
+
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
return context => {
|
|
434
|
+
const visit: ts.Visitor = node => {
|
|
435
|
+
|
|
436
|
+
const modifiers = ts.canHaveModifiers(node) ? (ts.getModifiers(node) || []).map(member => {
|
|
437
|
+
return ts.SyntaxKind[member.kind];
|
|
438
|
+
}) : [];
|
|
439
|
+
|
|
440
|
+
/*
|
|
441
|
+
const modifiers = (node.modifiers || []).map(member => {
|
|
442
|
+
return ts.SyntaxKind[member.kind];
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
if (modifiers.length) {
|
|
446
|
+
console.info({modifiers, modifiers2});
|
|
447
|
+
}
|
|
448
|
+
*/
|
|
449
|
+
|
|
450
|
+
const tags = GetDocTags(node);
|
|
451
|
+
|
|
452
|
+
const internal =
|
|
453
|
+
tags.some(test => config.exclude_tags.includes(test));
|
|
454
|
+
|
|
455
|
+
const exported = modifiers.includes('ExportKeyword');
|
|
456
|
+
const declared = modifiers.includes('DeclareKeyword');
|
|
457
|
+
const is_public = !(modifiers.includes('ProtectedKeyword') || modifiers.includes('PrivateKeyword'));
|
|
458
|
+
|
|
459
|
+
/*
|
|
460
|
+
if ((node as any).name && ts.isIdentifier((node as any).name)) {
|
|
461
|
+
const name = (node as any).name.escapedText.toString();
|
|
462
|
+
if (/treb/i.test(name)) {
|
|
463
|
+
console.info(name, node.kind, ts.SyntaxKind[node.kind] );
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
*/
|
|
467
|
+
|
|
468
|
+
/*
|
|
469
|
+
if ((node as any).name && ts.isIdentifier((node as any).name)) {
|
|
470
|
+
const name = (node as any).name.escapedText.toString();
|
|
471
|
+
if (/trebglobal$/i.test(name)) {
|
|
472
|
+
console.info({name, exported, internal, modifiers});
|
|
473
|
+
console.info(node);
|
|
474
|
+
console.info('');
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
*/
|
|
478
|
+
|
|
479
|
+
/*
|
|
480
|
+
if (exported && declared) {
|
|
481
|
+
if ((node as any).name && ts.isIdentifier((node as any).name)) {
|
|
482
|
+
const name = (node as any).name.escapedText.toString();
|
|
483
|
+
//if (/treb$/i.test(name)) {
|
|
484
|
+
console.info({name, exported, internal, modifiers});
|
|
485
|
+
// console.info(node);
|
|
486
|
+
// console.info('');
|
|
487
|
+
//}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
}
|
|
491
|
+
*/
|
|
492
|
+
|
|
493
|
+
if (ts.isModuleDeclaration(node)
|
|
494
|
+
|| ts.isClassDeclaration(node)
|
|
495
|
+
|| ts.isInterfaceDeclaration(node)
|
|
496
|
+
|| ts.isTypeAliasDeclaration(node)
|
|
497
|
+
|| ts.isEnumDeclaration(node)) {
|
|
498
|
+
|
|
499
|
+
if (exported && !internal) {
|
|
500
|
+
|
|
501
|
+
if (node.name && ts.isIdentifier(node.name)) {
|
|
502
|
+
|
|
503
|
+
if (!AddFoundType(node.name.escapedText.toString(), node.getFullText())) {
|
|
504
|
+
return undefined;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
containing_type.unshift(node.name.escapedText.toString());
|
|
508
|
+
|
|
509
|
+
if (ts.isClassDeclaration(node)) {
|
|
510
|
+
const name = node.name?.escapedText;
|
|
511
|
+
if (name && config.drop_generics.includes(name)) {
|
|
512
|
+
node = ts.factory.updateClassDeclaration(node,
|
|
513
|
+
// node.decorators,
|
|
514
|
+
node.modifiers,
|
|
515
|
+
node.name,
|
|
516
|
+
[], // node.typeParameters,
|
|
517
|
+
node.heritageClauses,
|
|
518
|
+
node.members);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (ts.isInterfaceDeclaration(node)) {
|
|
523
|
+
|
|
524
|
+
// drop any internals, so we don't reference types
|
|
525
|
+
|
|
526
|
+
node = ts.factory.updateInterfaceDeclaration(node,
|
|
527
|
+
// node.decorators,
|
|
528
|
+
node.modifiers,
|
|
529
|
+
node.name,
|
|
530
|
+
node.typeParameters,
|
|
531
|
+
node.heritageClauses,
|
|
532
|
+
node.members.filter(member => {
|
|
533
|
+
|
|
534
|
+
const member_tags = GetDocTags(member);
|
|
535
|
+
const internal = member_tags.some(test => config.exclude_tags.includes(test));
|
|
536
|
+
|
|
537
|
+
if (internal) {
|
|
538
|
+
return false;
|
|
539
|
+
}
|
|
540
|
+
return true;
|
|
541
|
+
|
|
542
|
+
}));
|
|
543
|
+
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const result = ts.visitEachChild(node, child => visit(child), context);
|
|
547
|
+
containing_type.shift();
|
|
548
|
+
return result;
|
|
549
|
+
|
|
550
|
+
}
|
|
551
|
+
else {
|
|
552
|
+
throw new Error('unhandled case (12)');
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
else {
|
|
556
|
+
return undefined; // do not recurse
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
else if (ts.isVariableStatement(node)) {
|
|
562
|
+
if (exported && !internal) {
|
|
563
|
+
|
|
564
|
+
// the type will be found, so we don't have to worry about that.
|
|
565
|
+
// should we be concerned with invalid/removed types? (...)
|
|
566
|
+
|
|
567
|
+
// we may see this more than once, if a file is included by
|
|
568
|
+
// other files. is there a better way to identify variables?
|
|
569
|
+
// maybe we should affirmatively declare exports with a tag
|
|
570
|
+
|
|
571
|
+
const text = node.getFullText();
|
|
572
|
+
args.exported_variables.push(text);
|
|
573
|
+
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
return undefined; // end
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
else if (ts.isExpressionWithTypeArguments(node)) {
|
|
581
|
+
if (ts.isIdentifier(node.expression)) {
|
|
582
|
+
const key = node.expression.escapedText.toString();
|
|
583
|
+
AddReferencedType(key, 0);
|
|
584
|
+
}
|
|
585
|
+
else if (ts.isQualifiedName(node.expression)) {
|
|
586
|
+
const stack = FlattenQualifiedName(node.expression);
|
|
587
|
+
if (stack.length) {
|
|
588
|
+
AddReferencedType(stack[0], 1);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
else if (ts.isTypeReferenceNode(node)) {
|
|
594
|
+
|
|
595
|
+
if (ts.isIdentifier(node.typeName)) {
|
|
596
|
+
const key = node.typeName.escapedText.toString();
|
|
597
|
+
AddReferencedType(key, 2);
|
|
598
|
+
}
|
|
599
|
+
else if (ts.isQualifiedName(node.typeName)) {
|
|
600
|
+
|
|
601
|
+
// do we want the qualified name, or just the thing we need
|
|
602
|
+
// to import (right-most)?
|
|
603
|
+
|
|
604
|
+
const stack = FlattenQualifiedName(node.typeName);
|
|
605
|
+
// AddReferencedType(FlattenQualifiedName(node.typeName).join('.'));
|
|
606
|
+
if (stack.length) {
|
|
607
|
+
AddReferencedType(stack[0], 3);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
}
|
|
611
|
+
else {
|
|
612
|
+
throw new Error('unhandled case (13)');
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
else if (ts.isPropertyDeclaration(node)
|
|
617
|
+
|| ts.isMethodDeclaration(node)
|
|
618
|
+
|| ts.isAccessor(node)) {
|
|
619
|
+
|
|
620
|
+
// FIXME: do we want static? in some cases, maybe yes...
|
|
621
|
+
// we should probably filter later, and on a case-by-case basis
|
|
622
|
+
|
|
623
|
+
// we're inside a method in a class... we should only get here
|
|
624
|
+
// if the containing class was exported. here we are only looking
|
|
625
|
+
// for types, and only on public methods. (same for properties;
|
|
626
|
+
// must be public).
|
|
627
|
+
|
|
628
|
+
if (ts.isIdentifier(node.name)) {
|
|
629
|
+
|
|
630
|
+
if (!is_public || internal) {
|
|
631
|
+
return undefined; // don't recurse
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
}
|
|
635
|
+
else {
|
|
636
|
+
throw new Error('unhandled case (15)');
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
else if (ts.isConstructorDeclaration(node)) {
|
|
642
|
+
|
|
643
|
+
if (!is_public || internal) {
|
|
644
|
+
return undefined; // don't recurse
|
|
645
|
+
}
|
|
646
|
+
else {
|
|
647
|
+
// console.info(node);
|
|
648
|
+
// console.info('public?', is_public, 'tags?', tags);
|
|
649
|
+
// throw new Error('no');
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
else if (ts.isImportDeclaration(node)) {
|
|
654
|
+
|
|
655
|
+
let target = node.moduleSpecifier.getText();
|
|
656
|
+
if (/^['"][\s\S]*?['"]$/.test(target)) {
|
|
657
|
+
target = target.substr(1, target.length - 2);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
if (node.importClause && ts.isImportClause(node.importClause)) {
|
|
661
|
+
if (node.importClause.namedBindings && ts.isNamedImports(node.importClause.namedBindings)) {
|
|
662
|
+
for (const element of node.importClause.namedBindings.elements) {
|
|
663
|
+
const name = element.name.escapedText.toString();
|
|
664
|
+
args.imported_types[name] = target;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
return undefined;
|
|
670
|
+
|
|
671
|
+
}
|
|
672
|
+
else if (ts.isExportDeclaration(node)) {
|
|
673
|
+
|
|
674
|
+
// this is export {A} from 'B', or export * from 'C'.
|
|
675
|
+
|
|
676
|
+
if (node.moduleSpecifier) {
|
|
677
|
+
let target = node.moduleSpecifier.getText();
|
|
678
|
+
if (/^['"][\s\S]*?['"]$/.test(target)) {
|
|
679
|
+
target = target.substr(1, target.length - 2);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const targets: string[] = args.recursive_targets[target] || [];
|
|
683
|
+
|
|
684
|
+
if (node.exportClause && ts.isNamedExports(node.exportClause)) {
|
|
685
|
+
for (const element of node.exportClause.elements) {
|
|
686
|
+
const name = element.name.escapedText.toString();
|
|
687
|
+
//if (args.types && args.types.includes(name)) {
|
|
688
|
+
// if (!args.recursive_targets[target]) { args.recursive_targets[target] = []; }
|
|
689
|
+
// args.recursive_targets[target].push(element.name.escapedText.toString());
|
|
690
|
+
//}
|
|
691
|
+
targets.push(name);
|
|
692
|
+
AddReferencedType(name, 4);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
else {
|
|
696
|
+
// this is 'export * from SRC' type
|
|
697
|
+
// if (!args.recursive_targets[target]) { args.recursive_targets[target] = []; }
|
|
698
|
+
// args.recursive_targets[target].push(...args.types);
|
|
699
|
+
targets.push('*');
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// console.info(targets);
|
|
703
|
+
|
|
704
|
+
args.recursive_targets[target] = targets;
|
|
705
|
+
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
return undefined;
|
|
709
|
+
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
return ts.visitEachChild(node, child => visit(child), context);
|
|
713
|
+
}
|
|
714
|
+
return node => ts.visitNode(node, visit);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
let invoke = 0;
|
|
719
|
+
|
|
720
|
+
const lookups: Record<string, boolean|string> = {};
|
|
721
|
+
const master: Record<string, string> = {};
|
|
722
|
+
const exported_variables: string[] = [];
|
|
723
|
+
|
|
724
|
+
let var_index = 0;
|
|
725
|
+
|
|
726
|
+
const ReadTypes = async (file: string, types?: string[], origination = 'C', depth = 0, stack: string[] = []): Promise<ReadTypeArgs> => {
|
|
727
|
+
|
|
728
|
+
// console.info('read types:', file, types);
|
|
729
|
+
|
|
730
|
+
if (stack.includes(file)) {
|
|
731
|
+
console.info(file, stack);
|
|
732
|
+
throw new Error('circular');
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
if (++invoke > 1e6) {
|
|
736
|
+
console.info(file, stack);
|
|
737
|
+
throw new Error('runaway');
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// console.info("R", file, (types||[]).join(', '));
|
|
741
|
+
|
|
742
|
+
/*
|
|
743
|
+
if (types && types.includes('Sheet')) {
|
|
744
|
+
console.info('want sheet', file, stack);
|
|
745
|
+
throw new Error('want sheet');
|
|
746
|
+
}
|
|
747
|
+
*/
|
|
748
|
+
|
|
749
|
+
let depth_prefix = '';
|
|
750
|
+
for (let i = 0; i < depth; i++) { depth_prefix += ' '; }
|
|
751
|
+
|
|
752
|
+
const RelativeFilePath = (key: string): string => {
|
|
753
|
+
for (const prefix of Object.keys(config.map)) {
|
|
754
|
+
if (key.startsWith(prefix)) { // should === ?
|
|
755
|
+
const replaced = key.replace(prefix, config.map[prefix]);
|
|
756
|
+
return path.join(config_dir, replaced);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
if (key.startsWith('.')) {
|
|
761
|
+
return path.join(path.dirname(file), key + '.d.ts');
|
|
762
|
+
}
|
|
763
|
+
else if (/\//.test(key)) {
|
|
764
|
+
return path.join(config_dir, config.root, key + '.d.ts');
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
return path.join(config_dir, config.root, key, 'src', 'index.d.ts');
|
|
768
|
+
// return path.join(config_dir, config.root, key, 'src', 'index.d.ts');
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
|
|
772
|
+
// console.info("READ", depth_prefix, origination, file, types);
|
|
773
|
+
|
|
774
|
+
const args: ReadTypeArgs = {
|
|
775
|
+
types,
|
|
776
|
+
recursive_targets: {},
|
|
777
|
+
found_types: {},
|
|
778
|
+
referenced_types: {},
|
|
779
|
+
referenced_type_map: {},
|
|
780
|
+
imported_types: {},
|
|
781
|
+
extra_types: {},
|
|
782
|
+
exported_variables: [],
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
const text = await fs.promises.readFile(file, { encoding: 'utf8' });
|
|
786
|
+
const node = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true);
|
|
787
|
+
|
|
788
|
+
ts.transform(node, [CollectDependencyTransformer(args)]);
|
|
789
|
+
|
|
790
|
+
let keys = Object.keys(args.referenced_types);
|
|
791
|
+
const found = Object.keys(args.found_types);
|
|
792
|
+
|
|
793
|
+
// console.info("T", (types||[]).join(', '))
|
|
794
|
+
// console.info(' K1', keys.join(', '));
|
|
795
|
+
|
|
796
|
+
// we can drop anything from keys that does not have a proper
|
|
797
|
+
// containing type... although the containing type may _itself_
|
|
798
|
+
// have a valid containing type... and so on...
|
|
799
|
+
|
|
800
|
+
// what we should do is climb up the containing type list. note
|
|
801
|
+
// that there could be more than one highest-level type...
|
|
802
|
+
|
|
803
|
+
//============================================================================
|
|
804
|
+
// Q: what is this for? it's broken. temporarily removing.
|
|
805
|
+
//============================================================================
|
|
806
|
+
|
|
807
|
+
const containing_keys = Object.keys(args.referenced_type_map);
|
|
808
|
+
|
|
809
|
+
/*
|
|
810
|
+
{
|
|
811
|
+
fs.writeFileSync('check.json', JSON.stringify(args.referenced_type_map, undefined, 2), {encoding: 'utf8'});
|
|
812
|
+
}
|
|
813
|
+
*/
|
|
814
|
+
|
|
815
|
+
const ResolveContainingTypes = (base: string, list: string[] = [], depth = 0) => {
|
|
816
|
+
// find any types that contain this type
|
|
817
|
+
|
|
818
|
+
/*
|
|
819
|
+
let s = '';
|
|
820
|
+
for (let i = 0; i< depth; i++) s += ' ';
|
|
821
|
+
console.info(s, 'rct', base, '');
|
|
822
|
+
*/
|
|
823
|
+
|
|
824
|
+
for (const container of containing_keys) {
|
|
825
|
+
if (args.referenced_type_map[container].includes(base)) {
|
|
826
|
+
if (!list.includes(container)) {
|
|
827
|
+
// console.info(s, ' check [2]', container);
|
|
828
|
+
list.push(container);
|
|
829
|
+
//const sublist = ResolveContainingTypes(container, list, depth + 1);
|
|
830
|
+
ResolveContainingTypes(container, list, depth + 1);
|
|
831
|
+
|
|
832
|
+
// list.push(...sublist);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
return list;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
const ResolveContainingTypes = (base: string, list: string[] = []) => {
|
|
841
|
+
|
|
842
|
+
// find any types that contain this type
|
|
843
|
+
for (const container of containing_keys) {
|
|
844
|
+
if (args.referenced_type_map[container].includes(base)) {
|
|
845
|
+
if (!list.includes(container)) {
|
|
846
|
+
list.push(container);
|
|
847
|
+
const sublist = ResolveContainingTypes(container, list);
|
|
848
|
+
list.push(...sublist);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
return list;
|
|
853
|
+
};
|
|
854
|
+
*/
|
|
855
|
+
|
|
856
|
+
// console.info('\n');
|
|
857
|
+
|
|
858
|
+
if (types) {
|
|
859
|
+
keys = keys.filter(key => {
|
|
860
|
+
const list = ResolveContainingTypes(key);
|
|
861
|
+
for (const entry of list) {
|
|
862
|
+
if (types.includes(entry)) { return true; }
|
|
863
|
+
}
|
|
864
|
+
// console.info("DROPPING", key);
|
|
865
|
+
return false;
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
// console.info(' KX', args.referenced_type_map);
|
|
870
|
+
// console.info(' K2', keys.join(', '));
|
|
871
|
+
// console.info(' F1', found.join(', '));
|
|
872
|
+
|
|
873
|
+
// we may have referenced types from the same file, in which case we
|
|
874
|
+
// need to add them to our "found" list.
|
|
875
|
+
|
|
876
|
+
for (const extra of Object.keys(args.extra_types)) {
|
|
877
|
+
if (keys.includes(extra) && !found.includes(extra)) {
|
|
878
|
+
found.push(extra);
|
|
879
|
+
args.found_types[extra] = args.extra_types[extra];
|
|
880
|
+
lookups[`${file}:${extra}`] = true;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// console.info(' F2', found.join(', '));
|
|
885
|
+
|
|
886
|
+
const mapped: Record<string, string[]> = {};
|
|
887
|
+
|
|
888
|
+
// if we were looking for a particular type in this file, did we
|
|
889
|
+
// find it? note that we're setting a boolean here, indicating simple
|
|
890
|
+
// found or not found at this point.
|
|
891
|
+
|
|
892
|
+
if (types) {
|
|
893
|
+
for (const type of types) {
|
|
894
|
+
lookups[`${file}:${type}`] = found.includes(type);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
/*
|
|
899
|
+
console.info('file:', file);
|
|
900
|
+
console.info('want:', types ? types : 'all');
|
|
901
|
+
console.info('found:', found);
|
|
902
|
+
console.info('recursive:', args.recursive_targets);
|
|
903
|
+
console.info('');
|
|
904
|
+
*/
|
|
905
|
+
|
|
906
|
+
const recursive = Object.keys(args.recursive_targets);
|
|
907
|
+
// console.info({recursive});
|
|
908
|
+
|
|
909
|
+
if (recursive.length) {
|
|
910
|
+
|
|
911
|
+
let filtered: string[] | undefined;
|
|
912
|
+
if (types) {
|
|
913
|
+
filtered = [];
|
|
914
|
+
for (const type of types) {
|
|
915
|
+
if (!found.includes(type)) {
|
|
916
|
+
filtered.push(type);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
// console.info({types, found, filtered});
|
|
922
|
+
|
|
923
|
+
if (!filtered || filtered.length) {
|
|
924
|
+
for (const key of recursive) {
|
|
925
|
+
const file_path = RelativeFilePath(key);
|
|
926
|
+
|
|
927
|
+
let sublist: string[] | undefined = args.recursive_targets[key];
|
|
928
|
+
let result: ReadTypeArgs;
|
|
929
|
+
|
|
930
|
+
// console.info(0, {file_path, key, sublist, filtered});
|
|
931
|
+
|
|
932
|
+
if (sublist.includes('*')) {
|
|
933
|
+
sublist = filtered;
|
|
934
|
+
}
|
|
935
|
+
else if (filtered) {
|
|
936
|
+
// console.info({sublist, filtered})
|
|
937
|
+
sublist = sublist.filter(test => (filtered||[]).includes(test));
|
|
938
|
+
}
|
|
939
|
+
else {
|
|
940
|
+
// console.info("using sublist without filter:", sublist);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// console.info(1, {file_path, key, sublist});
|
|
944
|
+
|
|
945
|
+
// NOW filter on whether we've checked this path for this
|
|
946
|
+
// type before. if so, even if we missed, we can drop it.
|
|
947
|
+
|
|
948
|
+
sublist = (sublist||[]).filter(test => {
|
|
949
|
+
const composite = `${file_path}:${test}`;
|
|
950
|
+
const check = lookups[composite];
|
|
951
|
+
return typeof check === 'undefined';
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
// console.info(2, {sublist});
|
|
955
|
+
|
|
956
|
+
if (sublist.length) {
|
|
957
|
+
result = await ReadTypes(file_path, sublist, 'X', depth + 1, [...stack, file]);
|
|
958
|
+
const resolved = Object.keys(result.found_types);
|
|
959
|
+
|
|
960
|
+
// console.info({resolved});
|
|
961
|
+
|
|
962
|
+
// if we found a type in a child that we were looking for, we can
|
|
963
|
+
// point our record (which should be false) to the child record
|
|
964
|
+
|
|
965
|
+
// UPDATE: this changes a bit when we have "extra" types, which
|
|
966
|
+
// were not originally referenced... in that case our record could
|
|
967
|
+
// be undefined, or even a string...
|
|
968
|
+
|
|
969
|
+
for (const test of resolved) {
|
|
970
|
+
const ours = `${file}:${test}`;
|
|
971
|
+
const theirs = `${file_path}:${test}`;
|
|
972
|
+
// console.info("CHECK 1", ours, master[ours], theirs, master[theirs]);
|
|
973
|
+
|
|
974
|
+
// validate
|
|
975
|
+
if (/*(lookups[ours] === false || lookups[ours] === undefined) &&*/ lookups[theirs] === true) {
|
|
976
|
+
lookups[ours] = theirs;
|
|
977
|
+
}
|
|
978
|
+
else {
|
|
979
|
+
// console.info("CHECK 1", ours, lookups[ours], theirs, lookups[theirs]);
|
|
980
|
+
// console.info("F", file);
|
|
981
|
+
throw new Error('??');
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
if (filtered) {
|
|
987
|
+
filtered = (filtered || []).filter(test => !resolved.includes(test));
|
|
988
|
+
if (!filtered.length) { break; }
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
for (const key of keys) {
|
|
999
|
+
if (!found.includes(key) && args.imported_types[key]) {
|
|
1000
|
+
const source = args.imported_types[key];
|
|
1001
|
+
const list = mapped[source] || [];
|
|
1002
|
+
mapped[source] = [...list, key];
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
for (const key of found) {
|
|
1007
|
+
master[key] = args.found_types[key];
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
for (const statement of args.exported_variables) {
|
|
1011
|
+
if (!exported_variables.includes(statement)) {
|
|
1012
|
+
master[`__variable_${var_index++}`] = statement;
|
|
1013
|
+
// console.info(statement);
|
|
1014
|
+
exported_variables.push(statement);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// console.info(file, Object.keys(mapped).join(', '));
|
|
1019
|
+
|
|
1020
|
+
/*
|
|
1021
|
+
if (!types) {
|
|
1022
|
+
console.info("I AM TOP")
|
|
1023
|
+
console.info(mapped);
|
|
1024
|
+
}
|
|
1025
|
+
*/
|
|
1026
|
+
|
|
1027
|
+
for (const key of Object.keys(mapped)) {
|
|
1028
|
+
|
|
1029
|
+
let list = mapped[key];
|
|
1030
|
+
const file_path = RelativeFilePath(key);
|
|
1031
|
+
|
|
1032
|
+
// filter types we've already read from this file
|
|
1033
|
+
list = list.filter(test => {
|
|
1034
|
+
const composite = `${file_path}:${test}`;
|
|
1035
|
+
const check = lookups[composite];
|
|
1036
|
+
return typeof check === 'undefined';
|
|
1037
|
+
});
|
|
1038
|
+
|
|
1039
|
+
if (list.length) {
|
|
1040
|
+
await ReadTypes(file_path, list, 'I', depth + 1, [...stack, file]);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
// if (2>1) throw new Error('ending after 1st import')
|
|
1044
|
+
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// console.info("ARGS", args, '\n');
|
|
1048
|
+
|
|
1049
|
+
return args;
|
|
1050
|
+
|
|
1051
|
+
};
|
|
1052
|
+
|
|
1053
|
+
const Run = async () => {
|
|
1054
|
+
|
|
1055
|
+
await ReadConfigData(config_file);
|
|
1056
|
+
console.info(config);
|
|
1057
|
+
|
|
1058
|
+
// read index file
|
|
1059
|
+
const index = path.join(config_dir, config.root, config.index);
|
|
1060
|
+
|
|
1061
|
+
await ReadTypes(index);
|
|
1062
|
+
|
|
1063
|
+
// console.info(`(done, ${invoke})`);
|
|
1064
|
+
|
|
1065
|
+
const text: string[] = [];
|
|
1066
|
+
for (const key of Object.keys(master)) {
|
|
1067
|
+
text.push(master[key]);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
const composite = text.join('\n');
|
|
1071
|
+
const node = ts.createSourceFile('composite', composite, ts.ScriptTarget.Latest, true);
|
|
1072
|
+
const result = ts.transform(node, [CleanTransformer()])
|
|
1073
|
+
|
|
1074
|
+
const printer = ts.createPrinter();
|
|
1075
|
+
let printed = printer.printFile(result.transformed[0]); // FIXME: options
|
|
1076
|
+
|
|
1077
|
+
// TS doesn't really like spaces
|
|
1078
|
+
printed = printed.replace(/(\s+?\/\*)/g, '\n$1');
|
|
1079
|
+
|
|
1080
|
+
// prepend any include files
|
|
1081
|
+
for (let include of config.include) {
|
|
1082
|
+
include = path.join(config_dir, include);
|
|
1083
|
+
const text = await fs.promises.readFile(include, {encoding: 'utf8'});
|
|
1084
|
+
printed = text + printed;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
if (api_version) {
|
|
1088
|
+
const banner = `/*! API v${api_version}. Copyright 2018-${new Date().getFullYear()} trebco, llc. All rights reserved. LGPL: https://treb.app/license */`;
|
|
1089
|
+
printed = banner + '\n' + printed;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
// can't figure out how to transform jsdoc nodes using transformers.
|
|
1093
|
+
// so, back to hacks. the aim here is to remove @privateRemarks, up
|
|
1094
|
+
// to the next tag (@) or close comment (*/). this often results in
|
|
1095
|
+
// an extra empty line in the comment, which is unfortunate but not
|
|
1096
|
+
// the end of the world.
|
|
1097
|
+
|
|
1098
|
+
printed = printed.replace(/(\s*\*)\s*@privateRemarks[\s\S]*?((?: @|\*\/))/g, '$1$2');
|
|
1099
|
+
|
|
1100
|
+
//
|
|
1101
|
+
// attempting to clean up... this somewhat confusing regexp
|
|
1102
|
+
// is intended to convert
|
|
1103
|
+
//
|
|
1104
|
+
// /**
|
|
1105
|
+
// * build version
|
|
1106
|
+
// *
|
|
1107
|
+
// **/
|
|
1108
|
+
// version: string;
|
|
1109
|
+
//
|
|
1110
|
+
// (caused by removing @privateRemarks) to
|
|
1111
|
+
//
|
|
1112
|
+
// /**
|
|
1113
|
+
// * build version
|
|
1114
|
+
// */
|
|
1115
|
+
// version: string;
|
|
1116
|
+
//
|
|
1117
|
+
printed = printed.replace(/(\*\n[ ]+)\*\*\//g, '*/')
|
|
1118
|
+
|
|
1119
|
+
if (config.output) {
|
|
1120
|
+
await fs.promises.writeFile(config.output, printed, {encoding: 'utf8'});
|
|
1121
|
+
}
|
|
1122
|
+
else {
|
|
1123
|
+
console.info(printed);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
|
|
1127
|
+
/*
|
|
1128
|
+
const text = await fs.promises.readFile(index, { encoding: 'utf8' });
|
|
1129
|
+
const node = ts.createSourceFile(index, text, ts.ScriptTarget.Latest, true);
|
|
1130
|
+
|
|
1131
|
+
const args = {
|
|
1132
|
+
recursive_targets: {},
|
|
1133
|
+
found_types: {},
|
|
1134
|
+
referenced_types: {},
|
|
1135
|
+
imported_types: {},
|
|
1136
|
+
};
|
|
1137
|
+
|
|
1138
|
+
const result = ts.transform(node, [CollectDependencyTransformer(args)]);
|
|
1139
|
+
|
|
1140
|
+
// console.info(Object.keys(args.found_types));
|
|
1141
|
+
// console.info(args.referenced_types);
|
|
1142
|
+
|
|
1143
|
+
const keys = Object.keys(args.referenced_types);
|
|
1144
|
+
keys.sort();
|
|
1145
|
+
|
|
1146
|
+
const found = Object.keys(args.found_types);
|
|
1147
|
+
const mapped: Record<string, string[]> = {};
|
|
1148
|
+
|
|
1149
|
+
for (const key of keys) {
|
|
1150
|
+
if (found.includes(key)) {
|
|
1151
|
+
// console.info(`${key} => FOUND`);
|
|
1152
|
+
}
|
|
1153
|
+
else if (args.imported_types[key]) {
|
|
1154
|
+
const source = args.imported_types[key];
|
|
1155
|
+
// console.info(`${key} => ${args.imported_types[key]}`);
|
|
1156
|
+
const list = mapped[source] || [];
|
|
1157
|
+
mapped[source] = [...list, key];
|
|
1158
|
+
}
|
|
1159
|
+
else {
|
|
1160
|
+
console.info(`${key} => missing!`);
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
console.info('---');
|
|
1164
|
+
console.info(mapped);
|
|
1165
|
+
*/
|
|
1166
|
+
|
|
1167
|
+
|
|
1168
|
+
};
|
|
1169
|
+
|
|
1170
|
+
Run();
|
|
1171
|
+
|
|
1172
|
+
|