@finos/legend-server-showcase-deployment 9.70.0 → 10.1.0
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/lib/ShowcaseRegistry.d.ts +4 -2
- package/lib/ShowcaseRegistry.d.ts.map +1 -1
- package/lib/ShowcaseRegistry.js +93 -4
- package/lib/ShowcaseRegistry.js.map +1 -1
- package/lib/ShowcaseRegistryServer.d.ts.map +1 -1
- package/lib/ShowcaseRegistryServer.js +3 -2
- package/lib/ShowcaseRegistryServer.js.map +1 -1
- package/lib/server.js +2 -1
- package/lib/server.js.map +1 -1
- package/package.json +8 -8
- package/src/ShowcaseRegistry.ts +133 -5
- package/src/ShowcaseRegistryServer.ts +14 -3
- package/src/server.ts +3 -1
@@ -13,7 +13,7 @@
|
|
13
13
|
* See the License for the specific language governing permissions and
|
14
14
|
* limitations under the License.
|
15
15
|
*/
|
16
|
-
import { type ShowcaseMetadata } from '@finos/legend-server-showcase';
|
16
|
+
import { Showcase, type ShowcaseMetadata, type ShowcaseTextSearchResult } from '@finos/legend-server-showcase';
|
17
17
|
import { type PlainObject } from '@finos/legend-shared';
|
18
18
|
export type ShowcaseRegistryConfig = {
|
19
19
|
datasources: {
|
@@ -25,9 +25,11 @@ export declare class ShowcaseRegistry {
|
|
25
25
|
private readonly RAW__metadata;
|
26
26
|
private readonly RAW__showcaseIndex;
|
27
27
|
private readonly showcasesIndex;
|
28
|
+
private readonly showcaseSearchEngine;
|
28
29
|
private constructor();
|
29
30
|
static initialize(config: ShowcaseRegistryConfig): Promise<ShowcaseRegistry>;
|
30
31
|
getShowcases(): PlainObject<ShowcaseMetadata>[];
|
31
|
-
getShowcase(path: string): PlainObject<
|
32
|
+
getShowcase(path: string): PlainObject<Showcase> | undefined;
|
33
|
+
search(searchText: string): Promise<ShowcaseTextSearchResult>;
|
32
34
|
}
|
33
35
|
//# sourceMappingURL=ShowcaseRegistry.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"ShowcaseRegistry.d.ts","sourceRoot":"","sources":["../src/ShowcaseRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,
|
1
|
+
{"version":3,"file":"ShowcaseRegistry.d.ts","sourceRoot":"","sources":["../src/ShowcaseRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,EACL,QAAQ,EACR,KAAK,gBAAgB,EAErB,KAAK,wBAAwB,EAC9B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAIL,KAAK,WAAW,EAEjB,MAAM,sBAAsB,CAAC;AAgC9B,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,EAAE;QACX,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,EAAE,CAAC;CACL,CAAC;AAEF,qBAAa,gBAAgB;IAE3B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuC;IACrE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAG/B;IAEJ,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA+B;IAC9D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAA8B;IAGnE,OAAO;WA6CM,UAAU,CACrB,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,gBAAgB,CAAC;IA6B5B,YAAY,IAAI,WAAW,CAAC,gBAAgB,CAAC,EAAE;IAI/C,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,GAAG,SAAS;IAItD,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC;CAqEpE"}
|
package/lib/ShowcaseRegistry.js
CHANGED
@@ -15,8 +15,8 @@
|
|
15
15
|
*/
|
16
16
|
import { get } from 'https';
|
17
17
|
import { readFileSync } from 'fs';
|
18
|
-
import { Showcase } from '@finos/legend-server-showcase';
|
19
|
-
import {} from '@finos/legend-shared';
|
18
|
+
import { Showcase, } from '@finos/legend-server-showcase';
|
19
|
+
import { ESM__FuzzySearchEngine, FuzzySearchEngine, promisify, getNonNullableEntry, } from '@finos/legend-shared';
|
20
20
|
async function fetchExternalLinkSiteData(url) {
|
21
21
|
return new Promise((resolve, reject) => {
|
22
22
|
get(url, (response) => {
|
@@ -36,7 +36,7 @@ async function fetchExternalLinkSiteData(url) {
|
|
36
36
|
const fetchShowcasesData = async (datasource) => {
|
37
37
|
let content;
|
38
38
|
if (datasource.url) {
|
39
|
-
content = await fetchExternalLinkSiteData(datasource.url);
|
39
|
+
content = JSON.parse(await fetchExternalLinkSiteData(datasource.url));
|
40
40
|
}
|
41
41
|
else if (datasource.path) {
|
42
42
|
content = JSON.parse(readFileSync(datasource.path, { encoding: 'utf-8' }));
|
@@ -48,8 +48,51 @@ export class ShowcaseRegistry {
|
|
48
48
|
RAW__metadata = [];
|
49
49
|
RAW__showcaseIndex = new Map();
|
50
50
|
showcasesIndex = new Map();
|
51
|
+
showcaseSearchEngine;
|
52
|
+
// private constructor to enforce singleton
|
51
53
|
constructor() {
|
52
|
-
//
|
54
|
+
// NOTE: due to the way we export the constructor of `FuzzySearchEngine`, when we run this with ESM
|
55
|
+
// we can remove this workaround once Fuse supports ESM
|
56
|
+
// See https://github.com/krisk/Fuse/pull/727
|
57
|
+
const FuzzySearchEngineConstructor =
|
58
|
+
// eslint-disable-next-line no-process-env
|
59
|
+
process.env.NODE_ENV === 'development'
|
60
|
+
? ESM__FuzzySearchEngine
|
61
|
+
: FuzzySearchEngine;
|
62
|
+
this.showcaseSearchEngine = new FuzzySearchEngineConstructor([], {
|
63
|
+
includeScore: true,
|
64
|
+
// NOTE: we must not sort/change the order in the grid since
|
65
|
+
// we want to ensure the element row is on top
|
66
|
+
shouldSort: false,
|
67
|
+
// Ignore location when computing the search score
|
68
|
+
// See https://fusejs.io/concepts/scoring-theory.html
|
69
|
+
ignoreLocation: true,
|
70
|
+
// This specifies the point the search gives up
|
71
|
+
// `0.0` means exact match where `1.0` would match anything
|
72
|
+
// We set a relatively low threshold to filter out irrelevant results
|
73
|
+
threshold: 0.2,
|
74
|
+
keys: [
|
75
|
+
{
|
76
|
+
name: 'title',
|
77
|
+
weight: 5,
|
78
|
+
},
|
79
|
+
{
|
80
|
+
name: 'description',
|
81
|
+
weight: 3,
|
82
|
+
},
|
83
|
+
{
|
84
|
+
name: 'path',
|
85
|
+
weight: 2,
|
86
|
+
},
|
87
|
+
{
|
88
|
+
name: 'documentation',
|
89
|
+
weight: 1,
|
90
|
+
},
|
91
|
+
],
|
92
|
+
// extended search allows for exact word match through single quote
|
93
|
+
// See https://fusejs.io/examples.html#extended-search
|
94
|
+
useExtendedSearch: true,
|
95
|
+
});
|
53
96
|
}
|
54
97
|
static async initialize(config) {
|
55
98
|
const registry = new ShowcaseRegistry();
|
@@ -69,6 +112,7 @@ export class ShowcaseRegistry {
|
|
69
112
|
}
|
70
113
|
});
|
71
114
|
}));
|
115
|
+
registry.showcaseSearchEngine.setCollection(Array.from(registry.showcasesIndex.values()));
|
72
116
|
return registry;
|
73
117
|
}
|
74
118
|
getShowcases() {
|
@@ -77,5 +121,50 @@ export class ShowcaseRegistry {
|
|
77
121
|
getShowcase(path) {
|
78
122
|
return this.RAW__showcaseIndex.get(path);
|
79
123
|
}
|
124
|
+
async search(searchText) {
|
125
|
+
const matches = [];
|
126
|
+
// NOTE: for text search, we only support case-insensitive search now
|
127
|
+
const lowerCaseSearchText = searchText.toLowerCase();
|
128
|
+
await Promise.all(Array.from(this.showcasesIndex.values()).map((showcase) => promisify(() => {
|
129
|
+
const result = {
|
130
|
+
path: showcase.path,
|
131
|
+
matches: [],
|
132
|
+
preview: [],
|
133
|
+
};
|
134
|
+
const previewLines = new Map();
|
135
|
+
const code = showcase.code;
|
136
|
+
const lines = code.split('\n');
|
137
|
+
lines.forEach((line, lineIdx) => {
|
138
|
+
const lowerCaseLine = line.toLowerCase();
|
139
|
+
let fromIdx = 0;
|
140
|
+
let currentMatchIdx = lowerCaseLine.indexOf(lowerCaseSearchText, fromIdx);
|
141
|
+
while (currentMatchIdx !== -1) {
|
142
|
+
const previewTextStartLineIdx = Math.max(lineIdx - 1, 0);
|
143
|
+
previewLines.set(previewTextStartLineIdx + 1, getNonNullableEntry(lines, previewTextStartLineIdx));
|
144
|
+
previewLines.set(lineIdx + 1, getNonNullableEntry(lines, lineIdx));
|
145
|
+
const previewTextEndLineIdx = Math.min(lineIdx + 1, lines.length - 1);
|
146
|
+
previewLines.set(previewTextEndLineIdx + 1, getNonNullableEntry(lines, previewTextEndLineIdx));
|
147
|
+
result.matches.push({
|
148
|
+
line: lineIdx + 1,
|
149
|
+
startColumn: currentMatchIdx + 1,
|
150
|
+
endColumn: currentMatchIdx + 1 + lowerCaseSearchText.length,
|
151
|
+
});
|
152
|
+
fromIdx = currentMatchIdx + lowerCaseSearchText.length;
|
153
|
+
currentMatchIdx = lowerCaseLine.indexOf(lowerCaseSearchText, fromIdx);
|
154
|
+
}
|
155
|
+
});
|
156
|
+
if (!result.matches.length) {
|
157
|
+
return;
|
158
|
+
}
|
159
|
+
result.preview = Array.from(previewLines.entries())
|
160
|
+
.map(([line, text]) => ({ line, text }))
|
161
|
+
.sort((a, b) => a.line - b.line);
|
162
|
+
matches.push(result);
|
163
|
+
})));
|
164
|
+
return {
|
165
|
+
showcases: Array.from(this.showcaseSearchEngine.search(searchText).values()).map((result) => result.item.path),
|
166
|
+
textMatches: matches,
|
167
|
+
};
|
168
|
+
}
|
80
169
|
}
|
81
170
|
//# sourceMappingURL=ShowcaseRegistry.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"ShowcaseRegistry.js","sourceRoot":"","sources":["../src/ShowcaseRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,
|
1
|
+
{"version":3,"file":"ShowcaseRegistry.js","sourceRoot":"","sources":["../src/ShowcaseRegistry.ts"],"names":[],"mappings":"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"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"ShowcaseRegistryServer.d.ts","sourceRoot":"","sources":["../src/ShowcaseRegistryServer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,KAAK,eAAe,EAAgC,MAAM,SAAS,CAAC;AAC7E,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,uBAAuB,CAAC;
|
1
|
+
{"version":3,"file":"ShowcaseRegistryServer.d.ts","sourceRoot":"","sources":["../src/ShowcaseRegistryServer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,KAAK,eAAe,EAAgC,MAAM,SAAS,CAAC;AAC7E,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,uBAAuB,CAAC;AAc/B,eAAO,MAAM,+BAA+B,WAClC,eAAe,UACf,sBAAsB,GAAG;IAC/B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC,KACA,QAAQ,IAAI,CA8Bd,CAAC"}
|
@@ -30,8 +30,9 @@ export const configureShowcaseRegistryServer = async (server, config) => {
|
|
30
30
|
}
|
31
31
|
await reply.send(registry.getShowcase(path));
|
32
32
|
});
|
33
|
-
server.get(`${baseUrl}/
|
34
|
-
|
33
|
+
server.get(`${baseUrl}/showcases/search`, async (request, reply) => {
|
34
|
+
const { searchText } = request.query;
|
35
|
+
await reply.send(await registry.search(searchText));
|
35
36
|
});
|
36
37
|
};
|
37
38
|
//# sourceMappingURL=ShowcaseRegistryServer.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"ShowcaseRegistryServer.js","sourceRoot":"","sources":["../src/ShowcaseRegistryServer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAsD,MAAM,SAAS,CAAC;AAC7E,OAAO,EACL,gBAAgB,GAEjB,MAAM,uBAAuB,CAAC;
|
1
|
+
{"version":3,"file":"ShowcaseRegistryServer.js","sourceRoot":"","sources":["../src/ShowcaseRegistryServer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAsD,MAAM,SAAS,CAAC;AAC7E,OAAO,EACL,gBAAgB,GAEjB,MAAM,uBAAuB,CAAC;AAc/B,MAAM,CAAC,MAAM,+BAA+B,GAAG,KAAK,EAClD,MAAuB,EACvB,MAEC,EACc,EAAE;IACjB,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC;IAE5C,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAC1D,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,GAAG,CACR,GAAG,OAAO,iBAAiB,EAC3B,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACvB,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QAChC,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ,EAAE;YACb,KAAK,CAAC,YAAY,EAAE,CAAC;YACrB,OAAO;SACR;QAED,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/C,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,GAAG,CACR,GAAG,OAAO,mBAAmB,EAC7B,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACvB,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;QAErC,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IACtD,CAAC,CACF,CAAC;AACJ,CAAC,CAAC"}
|
package/lib/server.js
CHANGED
@@ -17,6 +17,7 @@ import { existsSync, readFileSync } from 'fs';
|
|
17
17
|
import { fastify } from 'fastify';
|
18
18
|
import { fastifyCors } from '@fastify/cors';
|
19
19
|
import { configureShowcaseRegistryServer } from './ShowcaseRegistryServer.js';
|
20
|
+
const API_BASE_URL = '/api';
|
20
21
|
const configFilePath = process.argv[2] ?? './config.json';
|
21
22
|
if (!existsSync(configFilePath)) {
|
22
23
|
throw new Error(`Can't find config file at path '${configFilePath}'`);
|
@@ -28,7 +29,7 @@ const server = fastify({
|
|
28
29
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
29
30
|
server.register(fastifyCors, {});
|
30
31
|
await configureShowcaseRegistryServer(server, {
|
31
|
-
apiBaseUrl:
|
32
|
+
apiBaseUrl: API_BASE_URL,
|
32
33
|
datasources: config.datasources.map((datasource) => {
|
33
34
|
if (datasource.path) {
|
34
35
|
return {
|
package/lib/server.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AAG9E,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC;AAC1D,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE;IAC/B,MAAM,IAAI,KAAK,CAAC,mCAAmC,cAAc,GAAG,CAAC,CAAC;CACvE;AACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CACvB,YAAY,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CACP,CAAC;AAE/C,MAAM,MAAM,GAAG,OAAO,CAAC;IACrB,MAAM,EAAE,IAAI;CACb,CAAC,CAAC;AAEH,mEAAmE;AACnE,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AAEjC,MAAM,+BAA+B,CAAC,MAAM,EAAE;IAC5C,UAAU,EAAE,
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AAG9E,MAAM,YAAY,GAAG,MAAM,CAAC;AAE5B,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC;AAC1D,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE;IAC/B,MAAM,IAAI,KAAK,CAAC,mCAAmC,cAAc,GAAG,CAAC,CAAC;CACvE;AACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CACvB,YAAY,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CACP,CAAC;AAE/C,MAAM,MAAM,GAAG,OAAO,CAAC;IACrB,MAAM,EAAE,IAAI;CACb,CAAC,CAAC;AAEH,mEAAmE;AACnE,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AAEjC,MAAM,+BAA+B,CAAC,MAAM,EAAE;IAC5C,UAAU,EAAE,YAAY;IACxB,WAAW,EAAG,MAAiC,CAAC,WAAW,CAAC,GAAG,CAC7D,CAAC,UAAU,EAAE,EAAE;QACb,IAAI,UAAU,CAAC,IAAI,EAAE;YACnB,OAAO;gBACL,IAAI,EAAE,UAAU,CAAC,IAAI;aACtB,CAAC;SACH;QACD,OAAO,UAAU,CAAC;IACpB,CAAC,CACF;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,CACX;IACE,IAAI,EAAE,MAAM,CAAC,IAAI;IACjB,kEAAkE;IAClE,IAAI,EAAE,SAAS;CAChB,EACD,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACjB,IAAI,KAAK,EAAE;QACT,MAAM,KAAK,CAAC;KACb;AACH,CAAC,CACF,CAAC"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@finos/legend-server-showcase-deployment",
|
3
|
-
"version": "
|
3
|
+
"version": "10.1.0",
|
4
4
|
"description": "Legend Showcase server deployment",
|
5
5
|
"keywords": [
|
6
6
|
"legend",
|
@@ -51,21 +51,21 @@
|
|
51
51
|
},
|
52
52
|
"dependencies": {
|
53
53
|
"@fastify/cors": "8.3.0",
|
54
|
-
"@finos/legend-server-showcase": "0.0.
|
55
|
-
"@finos/legend-shared": "10.0.
|
56
|
-
"fastify": "4.
|
54
|
+
"@finos/legend-server-showcase": "0.0.5",
|
55
|
+
"@finos/legend-shared": "10.0.21",
|
56
|
+
"fastify": "4.20.0"
|
57
57
|
},
|
58
58
|
"devDependencies": {
|
59
|
-
"@finos/legend-dev-utils": "2.0.
|
59
|
+
"@finos/legend-dev-utils": "2.0.75",
|
60
60
|
"@jest/globals": "29.6.1",
|
61
61
|
"cross-env": "7.0.3",
|
62
|
-
"eslint": "8.
|
62
|
+
"eslint": "8.45.0",
|
63
63
|
"jest": "29.6.1",
|
64
|
-
"nodemon": "
|
64
|
+
"nodemon": "3.0.1",
|
65
65
|
"npm-run-all": "4.1.5",
|
66
66
|
"rimraf": "5.0.1",
|
67
67
|
"typescript": "5.1.6",
|
68
|
-
"webpack": "5.88.
|
68
|
+
"webpack": "5.88.2",
|
69
69
|
"webpack-bundle-analyzer": "4.9.0",
|
70
70
|
"webpack-cli": "5.1.4"
|
71
71
|
},
|
package/src/ShowcaseRegistry.ts
CHANGED
@@ -16,8 +16,19 @@
|
|
16
16
|
|
17
17
|
import { get } from 'https';
|
18
18
|
import { readFileSync } from 'fs';
|
19
|
-
import {
|
20
|
-
|
19
|
+
import {
|
20
|
+
Showcase,
|
21
|
+
type ShowcaseMetadata,
|
22
|
+
type ShowcaseTextSearchMatch,
|
23
|
+
type ShowcaseTextSearchResult,
|
24
|
+
} from '@finos/legend-server-showcase';
|
25
|
+
import {
|
26
|
+
ESM__FuzzySearchEngine,
|
27
|
+
FuzzySearchEngine,
|
28
|
+
promisify,
|
29
|
+
type PlainObject,
|
30
|
+
getNonNullableEntry,
|
31
|
+
} from '@finos/legend-shared';
|
21
32
|
|
22
33
|
async function fetchExternalLinkSiteData(url: string): Promise<string> {
|
23
34
|
return new Promise((resolve, reject) => {
|
@@ -42,7 +53,7 @@ const fetchShowcasesData = async (datasource: {
|
|
42
53
|
}): Promise<PlainObject<Showcase>[]> => {
|
43
54
|
let content: unknown;
|
44
55
|
if (datasource.url) {
|
45
|
-
content = await fetchExternalLinkSiteData(datasource.url);
|
56
|
+
content = JSON.parse(await fetchExternalLinkSiteData(datasource.url));
|
46
57
|
} else if (datasource.path) {
|
47
58
|
content = JSON.parse(readFileSync(datasource.path, { encoding: 'utf-8' }));
|
48
59
|
}
|
@@ -65,9 +76,52 @@ export class ShowcaseRegistry {
|
|
65
76
|
>();
|
66
77
|
|
67
78
|
private readonly showcasesIndex = new Map<string, Showcase>();
|
79
|
+
private readonly showcaseSearchEngine: FuzzySearchEngine<Showcase>;
|
68
80
|
|
81
|
+
// private constructor to enforce singleton
|
69
82
|
private constructor() {
|
70
|
-
//
|
83
|
+
// NOTE: due to the way we export the constructor of `FuzzySearchEngine`, when we run this with ESM
|
84
|
+
// we can remove this workaround once Fuse supports ESM
|
85
|
+
// See https://github.com/krisk/Fuse/pull/727
|
86
|
+
const FuzzySearchEngineConstructor =
|
87
|
+
// eslint-disable-next-line no-process-env
|
88
|
+
process.env.NODE_ENV === 'development'
|
89
|
+
? ESM__FuzzySearchEngine
|
90
|
+
: FuzzySearchEngine;
|
91
|
+
this.showcaseSearchEngine = new FuzzySearchEngineConstructor([], {
|
92
|
+
includeScore: true,
|
93
|
+
// NOTE: we must not sort/change the order in the grid since
|
94
|
+
// we want to ensure the element row is on top
|
95
|
+
shouldSort: false,
|
96
|
+
// Ignore location when computing the search score
|
97
|
+
// See https://fusejs.io/concepts/scoring-theory.html
|
98
|
+
ignoreLocation: true,
|
99
|
+
// This specifies the point the search gives up
|
100
|
+
// `0.0` means exact match where `1.0` would match anything
|
101
|
+
// We set a relatively low threshold to filter out irrelevant results
|
102
|
+
threshold: 0.2,
|
103
|
+
keys: [
|
104
|
+
{
|
105
|
+
name: 'title',
|
106
|
+
weight: 5,
|
107
|
+
},
|
108
|
+
{
|
109
|
+
name: 'description',
|
110
|
+
weight: 3,
|
111
|
+
},
|
112
|
+
{
|
113
|
+
name: 'path',
|
114
|
+
weight: 2,
|
115
|
+
},
|
116
|
+
{
|
117
|
+
name: 'documentation',
|
118
|
+
weight: 1,
|
119
|
+
},
|
120
|
+
],
|
121
|
+
// extended search allows for exact word match through single quote
|
122
|
+
// See https://fusejs.io/examples.html#extended-search
|
123
|
+
useExtendedSearch: true,
|
124
|
+
});
|
71
125
|
}
|
72
126
|
|
73
127
|
static async initialize(
|
@@ -94,6 +148,10 @@ export class ShowcaseRegistry {
|
|
94
148
|
}),
|
95
149
|
);
|
96
150
|
|
151
|
+
registry.showcaseSearchEngine.setCollection(
|
152
|
+
Array.from(registry.showcasesIndex.values()),
|
153
|
+
);
|
154
|
+
|
97
155
|
return registry;
|
98
156
|
}
|
99
157
|
|
@@ -101,7 +159,77 @@ export class ShowcaseRegistry {
|
|
101
159
|
return this.RAW__metadata;
|
102
160
|
}
|
103
161
|
|
104
|
-
getShowcase(path: string): PlainObject<
|
162
|
+
getShowcase(path: string): PlainObject<Showcase> | undefined {
|
105
163
|
return this.RAW__showcaseIndex.get(path);
|
106
164
|
}
|
165
|
+
|
166
|
+
async search(searchText: string): Promise<ShowcaseTextSearchResult> {
|
167
|
+
const matches: ShowcaseTextSearchMatch[] = [];
|
168
|
+
// NOTE: for text search, we only support case-insensitive search now
|
169
|
+
const lowerCaseSearchText = searchText.toLowerCase();
|
170
|
+
await Promise.all(
|
171
|
+
Array.from(this.showcasesIndex.values()).map((showcase) =>
|
172
|
+
promisify(() => {
|
173
|
+
const result: ShowcaseTextSearchMatch = {
|
174
|
+
path: showcase.path,
|
175
|
+
matches: [],
|
176
|
+
preview: [],
|
177
|
+
};
|
178
|
+
const previewLines = new Map<number, string>();
|
179
|
+
const code = showcase.code;
|
180
|
+
const lines = code.split('\n');
|
181
|
+
lines.forEach((line, lineIdx) => {
|
182
|
+
const lowerCaseLine = line.toLowerCase();
|
183
|
+
let fromIdx = 0;
|
184
|
+
let currentMatchIdx = lowerCaseLine.indexOf(
|
185
|
+
lowerCaseSearchText,
|
186
|
+
fromIdx,
|
187
|
+
);
|
188
|
+
while (currentMatchIdx !== -1) {
|
189
|
+
const previewTextStartLineIdx = Math.max(lineIdx - 1, 0);
|
190
|
+
previewLines.set(
|
191
|
+
previewTextStartLineIdx + 1,
|
192
|
+
getNonNullableEntry(lines, previewTextStartLineIdx),
|
193
|
+
);
|
194
|
+
previewLines.set(
|
195
|
+
lineIdx + 1,
|
196
|
+
getNonNullableEntry(lines, lineIdx),
|
197
|
+
);
|
198
|
+
const previewTextEndLineIdx = Math.min(
|
199
|
+
lineIdx + 1,
|
200
|
+
lines.length - 1,
|
201
|
+
);
|
202
|
+
previewLines.set(
|
203
|
+
previewTextEndLineIdx + 1,
|
204
|
+
getNonNullableEntry(lines, previewTextEndLineIdx),
|
205
|
+
);
|
206
|
+
result.matches.push({
|
207
|
+
line: lineIdx + 1,
|
208
|
+
startColumn: currentMatchIdx + 1,
|
209
|
+
endColumn: currentMatchIdx + 1 + lowerCaseSearchText.length,
|
210
|
+
});
|
211
|
+
fromIdx = currentMatchIdx + lowerCaseSearchText.length;
|
212
|
+
currentMatchIdx = lowerCaseLine.indexOf(
|
213
|
+
lowerCaseSearchText,
|
214
|
+
fromIdx,
|
215
|
+
);
|
216
|
+
}
|
217
|
+
});
|
218
|
+
if (!result.matches.length) {
|
219
|
+
return;
|
220
|
+
}
|
221
|
+
result.preview = Array.from(previewLines.entries())
|
222
|
+
.map(([line, text]) => ({ line, text }))
|
223
|
+
.sort((a, b) => a.line - b.line);
|
224
|
+
matches.push(result);
|
225
|
+
}),
|
226
|
+
),
|
227
|
+
);
|
228
|
+
return {
|
229
|
+
showcases: Array.from(
|
230
|
+
this.showcaseSearchEngine.search(searchText).values(),
|
231
|
+
).map((result) => result.item.path),
|
232
|
+
textMatches: matches,
|
233
|
+
};
|
234
|
+
}
|
107
235
|
}
|
@@ -26,6 +26,12 @@ interface GetShowcaseRequest extends RequestGenericInterface {
|
|
26
26
|
};
|
27
27
|
}
|
28
28
|
|
29
|
+
interface TextSearchRequest extends RequestGenericInterface {
|
30
|
+
Querystring: {
|
31
|
+
searchText: string;
|
32
|
+
};
|
33
|
+
}
|
34
|
+
|
29
35
|
export const configureShowcaseRegistryServer = async (
|
30
36
|
server: FastifyInstance,
|
31
37
|
config: ShowcaseRegistryConfig & {
|
@@ -53,7 +59,12 @@ export const configureShowcaseRegistryServer = async (
|
|
53
59
|
},
|
54
60
|
);
|
55
61
|
|
56
|
-
server.get(
|
57
|
-
|
58
|
-
|
62
|
+
server.get<TextSearchRequest>(
|
63
|
+
`${baseUrl}/showcases/search`,
|
64
|
+
async (request, reply) => {
|
65
|
+
const { searchText } = request.query;
|
66
|
+
|
67
|
+
await reply.send(await registry.search(searchText));
|
68
|
+
},
|
69
|
+
);
|
59
70
|
};
|
package/src/server.ts
CHANGED
@@ -20,6 +20,8 @@ import { fastifyCors } from '@fastify/cors';
|
|
20
20
|
import { configureShowcaseRegistryServer } from './ShowcaseRegistryServer.js';
|
21
21
|
import type { ShowcaseRegistryConfig } from './ShowcaseRegistry.js';
|
22
22
|
|
23
|
+
const API_BASE_URL = '/api';
|
24
|
+
|
23
25
|
const configFilePath = process.argv[2] ?? './config.json';
|
24
26
|
if (!existsSync(configFilePath)) {
|
25
27
|
throw new Error(`Can't find config file at path '${configFilePath}'`);
|
@@ -36,7 +38,7 @@ const server = fastify({
|
|
36
38
|
server.register(fastifyCors, {});
|
37
39
|
|
38
40
|
await configureShowcaseRegistryServer(server, {
|
39
|
-
apiBaseUrl:
|
41
|
+
apiBaseUrl: API_BASE_URL,
|
40
42
|
datasources: (config as ShowcaseRegistryConfig).datasources.map(
|
41
43
|
(datasource) => {
|
42
44
|
if (datasource.path) {
|