placementt-core 1.400.1089 → 1.400.1090
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/callables/apprenticeships.d.ts +7 -0
- package/lib/callables/apprenticeships.js +3 -0
- package/lib/callables/apprenticeships.js.map +1 -1
- package/lib/callables/registry.d.ts +10 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/pathways.d.ts +170 -0
- package/lib/pathways.js +241 -0
- package/lib/pathways.js.map +1 -0
- package/lib/pathways.test.d.ts +1 -0
- package/lib/pathways.test.js +175 -0
- package/lib/pathways.test.js.map +1 -0
- package/lib/tasksAndTips.js +1 -1
- package/lib/tasksAndTips.js.map +1 -1
- package/lib/typeDefinitions.d.ts +218 -8
- package/lib/typeDefinitions.js.map +1 -1
- package/package.json +1 -1
- package/src/callables/apprenticeships.ts +3 -0
- package/src/index.ts +1 -0
- package/src/pathways.test.ts +193 -0
- package/src/pathways.ts +281 -0
- package/src/tasksAndTips.ts +1 -1
- package/src/typeDefinitions.ts +215 -9
|
@@ -27,18 +27,23 @@ export declare const apprenticeshipsCallables: {
|
|
|
27
27
|
unchanged: z.ZodNumber;
|
|
28
28
|
deleted: z.ZodNumber;
|
|
29
29
|
requests: z.ZodNumber;
|
|
30
|
+
/** Adverts stored without a SOC because their standard was not in the
|
|
31
|
+
* lmiMeta/apprenticeshipStandards crosswalk. */
|
|
32
|
+
unlinked: z.ZodOptional<z.ZodNumber>;
|
|
30
33
|
}, "strip", z.ZodTypeAny, {
|
|
31
34
|
deleted: number;
|
|
32
35
|
fetched: number;
|
|
33
36
|
written: number;
|
|
34
37
|
unchanged: number;
|
|
35
38
|
requests: number;
|
|
39
|
+
unlinked?: number | undefined;
|
|
36
40
|
}, {
|
|
37
41
|
deleted: number;
|
|
38
42
|
fetched: number;
|
|
39
43
|
written: number;
|
|
40
44
|
unchanged: number;
|
|
41
45
|
requests: number;
|
|
46
|
+
unlinked?: number | undefined;
|
|
42
47
|
}>;
|
|
43
48
|
/** Requests this step made, so an admin can see the pacing held. */
|
|
44
49
|
stepRequests: z.ZodNumber;
|
|
@@ -51,6 +56,7 @@ export declare const apprenticeshipsCallables: {
|
|
|
51
56
|
written: number;
|
|
52
57
|
unchanged: number;
|
|
53
58
|
requests: number;
|
|
59
|
+
unlinked?: number | undefined;
|
|
54
60
|
};
|
|
55
61
|
stepRequests: number;
|
|
56
62
|
cursor?: {
|
|
@@ -67,6 +73,7 @@ export declare const apprenticeshipsCallables: {
|
|
|
67
73
|
written: number;
|
|
68
74
|
unchanged: number;
|
|
69
75
|
requests: number;
|
|
76
|
+
unlinked?: number | undefined;
|
|
70
77
|
};
|
|
71
78
|
stepRequests: number;
|
|
72
79
|
cursor?: {
|
|
@@ -23,6 +23,9 @@ const syncTotals = zod_1.z.object({
|
|
|
23
23
|
unchanged: zod_1.z.number(),
|
|
24
24
|
deleted: zod_1.z.number(),
|
|
25
25
|
requests: zod_1.z.number(),
|
|
26
|
+
/** Adverts stored without a SOC because their standard was not in the
|
|
27
|
+
* lmiMeta/apprenticeshipStandards crosswalk. */
|
|
28
|
+
unlinked: zod_1.z.number().optional(),
|
|
26
29
|
});
|
|
27
30
|
exports.apprenticeshipsCallables = {
|
|
28
31
|
/** Run one crawl step now (about eight minutes of paced requests), starting
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apprenticeships.js","sourceRoot":"","sources":["../../src/callables/apprenticeships.ts"],"names":[],"mappings":";;;AAAA,6BAAsB;AAGtB;;;;;;;;;GASG;AAEH,MAAM,UAAU,GAAG,OAAC,CAAC,MAAM,CAAC;IACxB,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE;IACtB,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE;IACtB,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE;CACzB,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG,OAAC,CAAC,MAAM,CAAC;IACxB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;IACnB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;IACnB,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE;IACrB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;IACnB,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE;
|
|
1
|
+
{"version":3,"file":"apprenticeships.js","sourceRoot":"","sources":["../../src/callables/apprenticeships.ts"],"names":[],"mappings":";;;AAAA,6BAAsB;AAGtB;;;;;;;;;GASG;AAEH,MAAM,UAAU,GAAG,OAAC,CAAC,MAAM,CAAC;IACxB,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE;IACtB,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE;IACtB,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE;CACzB,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG,OAAC,CAAC,MAAM,CAAC;IACxB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;IACnB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;IACnB,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE;IACrB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;IACnB,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE;IACpB;oDACgD;IAChD,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAClC,CAAC,CAAC;AAEU,QAAA,wBAAwB,GAAG;IACpC;oCACgC;IAChC,0BAA0B,EAAE;QACxB,OAAO,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACrB,QAAQ,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE;YACjB,oEAAoE;YACpE,QAAQ,EAAE,OAAC,CAAC,OAAO,EAAE;YACrB,MAAM,EAAE,UAAU,CAAC,QAAQ,EAAE;YAC7B,MAAM,EAAE,UAAU;YAClB,oEAAoE;YACpE,YAAY,EAAE,OAAC,CAAC,MAAM,EAAE;SAC3B,CAAC;KACL;IACD;kCAC8B;IAC9B,0BAA0B,EAAE;QACxB,OAAO,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACrB,QAAQ,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,EAAE,EAAE,OAAC,CAAC,OAAO,CAAC,IAAI,CAAC;SACtB,CAAC;KACL;IACD,8DAA8D;IAC9D,+BAA+B,EAAE;QAC7B,OAAO,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACrB,QAAQ,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,MAAM,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;SAC9B,CAAC;KACL;CACoB,CAAC"}
|
|
@@ -337,18 +337,21 @@ export declare const allCallables: {
|
|
|
337
337
|
unchanged: z.ZodNumber;
|
|
338
338
|
deleted: z.ZodNumber;
|
|
339
339
|
requests: z.ZodNumber;
|
|
340
|
+
unlinked: z.ZodOptional<z.ZodNumber>;
|
|
340
341
|
}, "strip", z.ZodTypeAny, {
|
|
341
342
|
deleted: number;
|
|
342
343
|
fetched: number;
|
|
343
344
|
written: number;
|
|
344
345
|
unchanged: number;
|
|
345
346
|
requests: number;
|
|
347
|
+
unlinked?: number | undefined;
|
|
346
348
|
}, {
|
|
347
349
|
deleted: number;
|
|
348
350
|
fetched: number;
|
|
349
351
|
written: number;
|
|
350
352
|
unchanged: number;
|
|
351
353
|
requests: number;
|
|
354
|
+
unlinked?: number | undefined;
|
|
352
355
|
}>;
|
|
353
356
|
stepRequests: z.ZodNumber;
|
|
354
357
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -360,6 +363,7 @@ export declare const allCallables: {
|
|
|
360
363
|
written: number;
|
|
361
364
|
unchanged: number;
|
|
362
365
|
requests: number;
|
|
366
|
+
unlinked?: number | undefined;
|
|
363
367
|
};
|
|
364
368
|
stepRequests: number;
|
|
365
369
|
cursor?: {
|
|
@@ -376,6 +380,7 @@ export declare const allCallables: {
|
|
|
376
380
|
written: number;
|
|
377
381
|
unchanged: number;
|
|
378
382
|
requests: number;
|
|
383
|
+
unlinked?: number | undefined;
|
|
379
384
|
};
|
|
380
385
|
stepRequests: number;
|
|
381
386
|
cursor?: {
|
|
@@ -1646,18 +1651,21 @@ export declare const callableGroups: {
|
|
|
1646
1651
|
unchanged: z.ZodNumber;
|
|
1647
1652
|
deleted: z.ZodNumber;
|
|
1648
1653
|
requests: z.ZodNumber;
|
|
1654
|
+
unlinked: z.ZodOptional<z.ZodNumber>;
|
|
1649
1655
|
}, "strip", z.ZodTypeAny, {
|
|
1650
1656
|
deleted: number;
|
|
1651
1657
|
fetched: number;
|
|
1652
1658
|
written: number;
|
|
1653
1659
|
unchanged: number;
|
|
1654
1660
|
requests: number;
|
|
1661
|
+
unlinked?: number | undefined;
|
|
1655
1662
|
}, {
|
|
1656
1663
|
deleted: number;
|
|
1657
1664
|
fetched: number;
|
|
1658
1665
|
written: number;
|
|
1659
1666
|
unchanged: number;
|
|
1660
1667
|
requests: number;
|
|
1668
|
+
unlinked?: number | undefined;
|
|
1661
1669
|
}>;
|
|
1662
1670
|
stepRequests: z.ZodNumber;
|
|
1663
1671
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -1669,6 +1677,7 @@ export declare const callableGroups: {
|
|
|
1669
1677
|
written: number;
|
|
1670
1678
|
unchanged: number;
|
|
1671
1679
|
requests: number;
|
|
1680
|
+
unlinked?: number | undefined;
|
|
1672
1681
|
};
|
|
1673
1682
|
stepRequests: number;
|
|
1674
1683
|
cursor?: {
|
|
@@ -1685,6 +1694,7 @@ export declare const callableGroups: {
|
|
|
1685
1694
|
written: number;
|
|
1686
1695
|
unchanged: number;
|
|
1687
1696
|
requests: number;
|
|
1697
|
+
unlinked?: number | undefined;
|
|
1688
1698
|
};
|
|
1689
1699
|
stepRequests: number;
|
|
1690
1700
|
cursor?: {
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -38,6 +38,7 @@ __exportStar(require("./activities"), exports);
|
|
|
38
38
|
__exportStar(require("./activityLogging"), exports);
|
|
39
39
|
__exportStar(require("./lmi"), exports);
|
|
40
40
|
__exportStar(require("./lmiCategories"), exports);
|
|
41
|
+
__exportStar(require("./pathways"), exports);
|
|
41
42
|
__exportStar(require("./productResolver"), exports);
|
|
42
43
|
__exportStar(require("./pricing"), exports);
|
|
43
44
|
__exportStar(require("./invoicing"), exports);
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AACA,sDAAoC;AACpC,gEAA8C;AAC9C,0DAAwC;AACxC,2DAAyC;AACzC,kDAAgC;AAChC,uDAAqC;AACrC,4DAA0C;AAC1C,2DAAyC;AAEzC,oDAAkC;AAClC,8CAA4B;AAC5B,kDAAgC;AAChC,kDAAgC;AAChC,qDAAmC;AACnC,mDAAiC;AACjC,qDAAmC;AACnC,mDAAiC;AACjC,+CAA6B;AAC7B,oDAAkC;AAClC,wCAAsB;AACtB,kDAAgC;AAChC,oDAAkC;AAClC,4CAA0B;AAC1B,8CAA4B;AAC5B,2CAAyB;AACzB,kDAAgC;AAChC,uDAAqC;AACrC,oDAAkC;AAClC,kDAAgC;AAChC,0DAAwC;AACxC,iDAA+B;AAC/B,2DAAyC;AACzC,uDAAqC;AACrC,uDAAqC;AACrC,iDAA+B;AAC/B,8CAA4B;AAC5B,qDAAmC;AACnC,0CAAwB;AACxB,kDAAgC;AAChC,yCAAuB;AACvB,4DAA0C;AAC1C,kDAAgC;AAChC,iDAA+B;AAC/B,2CAAyB;AACzB,4DAA0C;AAC1C,oEAAiD;AACjD,yEAAuD;AACvD,kEAAgD;AAChD,kEAAgD;AAChD,oEAAkD;AAClD,yGAAuF;AACvF,0GAAwF;AACxF,+FAA6E;AAC7E,4DAA0C;AAC1C,oEAAkD;AAClD,iEAA+C;AAC/C,gEAA8C;AAC9C,2EAAyD;AACzD,6CAA2B;AAC3B,+CAA6B;AAC7B,8CAA4B;AAC5B,6DAAuE;AAA9D,2IAAA,OAAO,OAAuB"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AACA,sDAAoC;AACpC,gEAA8C;AAC9C,0DAAwC;AACxC,2DAAyC;AACzC,kDAAgC;AAChC,uDAAqC;AACrC,4DAA0C;AAC1C,2DAAyC;AAEzC,oDAAkC;AAClC,8CAA4B;AAC5B,kDAAgC;AAChC,kDAAgC;AAChC,qDAAmC;AACnC,mDAAiC;AACjC,qDAAmC;AACnC,mDAAiC;AACjC,+CAA6B;AAC7B,oDAAkC;AAClC,wCAAsB;AACtB,kDAAgC;AAChC,6CAA2B;AAC3B,oDAAkC;AAClC,4CAA0B;AAC1B,8CAA4B;AAC5B,2CAAyB;AACzB,kDAAgC;AAChC,uDAAqC;AACrC,oDAAkC;AAClC,kDAAgC;AAChC,0DAAwC;AACxC,iDAA+B;AAC/B,2DAAyC;AACzC,uDAAqC;AACrC,uDAAqC;AACrC,iDAA+B;AAC/B,8CAA4B;AAC5B,qDAAmC;AACnC,0CAAwB;AACxB,kDAAgC;AAChC,yCAAuB;AACvB,4DAA0C;AAC1C,kDAAgC;AAChC,iDAA+B;AAC/B,2CAAyB;AACzB,4DAA0C;AAC1C,oEAAiD;AACjD,yEAAuD;AACvD,kEAAgD;AAChD,kEAAgD;AAChD,oEAAkD;AAClD,yGAAuF;AACvF,0GAAwF;AACxF,+FAA6E;AAC7E,4DAA0C;AAC1C,oEAAkD;AAClD,iEAA+C;AAC/C,gEAA8C;AAC9C,2EAAyD;AACzD,6CAA2B;AAC3B,+CAA6B;AAC7B,8CAA4B;AAC5B,6DAAuE;AAA9D,2IAAA,OAAO,OAAuB"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pathways: the joins between the careers library (SOC 2020), the apprenticeship
|
|
3
|
+
* mirror and the university course mirror, and what a student's own interests
|
|
4
|
+
* mean as a filter over the two.
|
|
5
|
+
*
|
|
6
|
+
* Everything routes through the 4-digit SOC 2020 unit group. Neither mirror
|
|
7
|
+
* carries one directly, so each is one hop away:
|
|
8
|
+
*
|
|
9
|
+
* vacancy.larsCode ─► IfATE standard.occupationCode ─► skillsEngland[].stdCode ─► soc
|
|
10
|
+
* course.commonJobs[i] (a HESA label) ─► SOC 2020 group title ─► prefix ("213")
|
|
11
|
+
*
|
|
12
|
+
* The HESA labels are SOC groups at whatever level HESA chose — mostly minor
|
|
13
|
+
* groups, a few major or unit — so a course links to a *prefix*, and both
|
|
14
|
+
* indexes carry each code's full prefix chain (`socPrefixChain`) so one exact
|
|
15
|
+
* Algolia facet term can match at any level.
|
|
16
|
+
*
|
|
17
|
+
* The functions here are pure and shared: the backend importers use the chain
|
|
18
|
+
* and the label matcher, the web uses the student-side helpers to build the
|
|
19
|
+
* "For you" filter and to say why a row matched.
|
|
20
|
+
*/
|
|
21
|
+
import { HeCommonJobGroup, UserData } from "./typeDefinitions";
|
|
22
|
+
/**
|
|
23
|
+
* A SOC 2020 code's ancestors and itself, shortest first.
|
|
24
|
+
*
|
|
25
|
+
* Accepts a unit group, a sub-unit ("2134/03") or a preference key ("2134-03");
|
|
26
|
+
* only the leading digits count. A code shorter than four digits (a HESA label
|
|
27
|
+
* that resolved to a minor group) yields the chain up to its own length.
|
|
28
|
+
*
|
|
29
|
+
* @param {string} code the SOC 2020 code, any of the forms above.
|
|
30
|
+
* @return {string[]} e.g. ["2", "21", "213", "2134"]; empty for non-SOC input.
|
|
31
|
+
*/
|
|
32
|
+
export declare function socPrefixChain(code: string): string[];
|
|
33
|
+
/**
|
|
34
|
+
* The form HESA labels and ONS group titles are compared in.
|
|
35
|
+
*
|
|
36
|
+
* Case, punctuation and spacing differ between the two sources ("Teaching
|
|
37
|
+
* Professionals" vs "Teaching professionals", "(RandD)" vs "(R&D)"), and one
|
|
38
|
+
* HESA label is singular where ONS is plural. Nothing semantic is done: if a
|
|
39
|
+
* future label needs more than this, it belongs in `unmatched`, not here.
|
|
40
|
+
*
|
|
41
|
+
* @param {string} title a label or group title.
|
|
42
|
+
* @return {string} the comparison key.
|
|
43
|
+
*/
|
|
44
|
+
export declare function normaliseSocGroupTitle(title: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* The SOC 2020 group a HESA common-job label names.
|
|
47
|
+
*
|
|
48
|
+
* @param {string} label the label as JOBLIST prints it.
|
|
49
|
+
* @param {{[code: string]: string}} titles the SOC hierarchy, code → title.
|
|
50
|
+
* @return {string|undefined} the group code, or undefined for a label no
|
|
51
|
+
* title matches.
|
|
52
|
+
*/
|
|
53
|
+
export declare function socPrefixForLabel(label: string, titles: {
|
|
54
|
+
[code: string]: string;
|
|
55
|
+
}): string | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* The 3-digit minor groups an interest category covers, plus any unit groups
|
|
58
|
+
* filed under it by override. Sorted, so a filter built from it is stable.
|
|
59
|
+
*
|
|
60
|
+
* @param {string} category one of CAREER_LIBRARY_CATEGORIES.
|
|
61
|
+
* @return {string[]} the codes; empty for an unknown category.
|
|
62
|
+
*/
|
|
63
|
+
export declare function socCodesForCategory(category: string): string[];
|
|
64
|
+
/** One reason a course or vacancy is recommended: a hearted job, or an
|
|
65
|
+
* interest category. */
|
|
66
|
+
export type ForYouSource = {
|
|
67
|
+
kind: "job";
|
|
68
|
+
/** The preference key, so a chip can open the job page. */
|
|
69
|
+
key: string;
|
|
70
|
+
title: string;
|
|
71
|
+
/** The 4-digit SOC. */
|
|
72
|
+
codes: string[];
|
|
73
|
+
} | {
|
|
74
|
+
kind: "category";
|
|
75
|
+
title: string;
|
|
76
|
+
/** The category's minor groups and overridden unit groups. */
|
|
77
|
+
codes: string[];
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* What a student's careers tab says they are interested in, as filter sources.
|
|
81
|
+
*
|
|
82
|
+
* Hearted jobs first (exact unit groups), then interest categories (sets of
|
|
83
|
+
* minor groups), in the order the student holds them. The categories are the
|
|
84
|
+
* live set if they have edited it, otherwise their latest survey answer — the
|
|
85
|
+
* same rule the library sidebar shows them under.
|
|
86
|
+
*
|
|
87
|
+
* @param {Pick<UserData, "currentJobPreferences"|"currentCareerInterests"|"aspirationHistory">} user the student.
|
|
88
|
+
* @return {ForYouSource[]} possibly empty, in which case there is nothing to recommend from.
|
|
89
|
+
*/
|
|
90
|
+
export declare function forYouSources(user?: Pick<UserData, "currentJobPreferences" | "currentCareerInterests" | "aspirationHistory">): ForYouSource[];
|
|
91
|
+
/** The facet terms a "For you" search filters each index on. */
|
|
92
|
+
export type ForYouFilter = {
|
|
93
|
+
/** Exact codes — a vacancy's chain always reaches unit level, so a
|
|
94
|
+
* hearted 2134 or an interest's 213 is matched as itself. */
|
|
95
|
+
vacancyTerms: string[];
|
|
96
|
+
/** Codes and every ancestor — a course's label can sit at any level, so
|
|
97
|
+
* a hearted 2134 must also find a course filed under "213" or "21". */
|
|
98
|
+
courseTerms: string[];
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Turn the sources into the two term lists, deduped and sorted.
|
|
102
|
+
*
|
|
103
|
+
* @param {ForYouSource[]} sources from `forYouSources`, possibly narrowed to
|
|
104
|
+
* the chips the student tapped.
|
|
105
|
+
* @return {ForYouFilter} empty lists when there are no sources.
|
|
106
|
+
*/
|
|
107
|
+
export declare function forYouFilter(sources: ForYouSource[]): ForYouFilter;
|
|
108
|
+
/**
|
|
109
|
+
* Which source a row is there because of.
|
|
110
|
+
*
|
|
111
|
+
* A row matches a source code when the row sits under the code (a vacancy at
|
|
112
|
+
* 2134 under an interest's 213) or the code sits under the row's own group (a
|
|
113
|
+
* course filed under "213" for a hearted 2134). Sharing an ancestor is not
|
|
114
|
+
* enough — 2211 and 2134 both start with "2" and have nothing to do with each
|
|
115
|
+
* other — so the row side is compared at the ends of its chains, never at
|
|
116
|
+
* an ancestor. The longest such overlap wins, which is what makes a hearted
|
|
117
|
+
* job beat a category covering the same minor group, and the depth comes
|
|
118
|
+
* back so a list can sort exact matches above group-level ones.
|
|
119
|
+
*
|
|
120
|
+
* @param {string[]} rowPrefixes the record's `socPrefixes`.
|
|
121
|
+
* @param {ForYouSource[]} sources the sources the filter was built from.
|
|
122
|
+
* @return {{source: ForYouSource, depth: number}|undefined} the best source,
|
|
123
|
+
* or undefined when nothing overlaps (a row from an unfiltered search).
|
|
124
|
+
*/
|
|
125
|
+
export declare function forYouMatch(rowPrefixes: string[] | undefined, sources: ForYouSource[]): {
|
|
126
|
+
source: ForYouSource;
|
|
127
|
+
depth: number;
|
|
128
|
+
} | undefined;
|
|
129
|
+
/** Why a course is recommended: the source it matched and, where the course
|
|
130
|
+
* carries its common-job groups, the group that did the matching with its
|
|
131
|
+
* share of graduates. */
|
|
132
|
+
export type ForYouCourseMatch = {
|
|
133
|
+
source: ForYouSource;
|
|
134
|
+
depth: number;
|
|
135
|
+
group?: HeCommonJobGroup;
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Which source a course matched, and through which of its common-job groups.
|
|
139
|
+
*
|
|
140
|
+
* The course's `socPrefixes` say whether it matches at all; its
|
|
141
|
+
* `commonJobGroups` say which group did it, and that group's `perc` is the
|
|
142
|
+
* figure a row quotes — "41% went into information technology professionals".
|
|
143
|
+
* Where two groups match, the deeper one wins, then the larger share. A course
|
|
144
|
+
* indexed before the groups existed still matches on its prefixes, just with
|
|
145
|
+
* no group to quote.
|
|
146
|
+
*
|
|
147
|
+
* @param {object} course the index record, or the part of it that matters.
|
|
148
|
+
* @param {string[]} [course.socPrefixes] its prefix chains.
|
|
149
|
+
* @param {HeCommonJobGroup[]} [course.commonJobGroups] its groups.
|
|
150
|
+
* @param {ForYouSource[]} sources the sources the filter was built from.
|
|
151
|
+
* @return {ForYouCourseMatch|undefined} the match, or nothing.
|
|
152
|
+
*/
|
|
153
|
+
export declare function forYouCourseMatch(course: {
|
|
154
|
+
socPrefixes?: string[];
|
|
155
|
+
commonJobGroups?: HeCommonJobGroup[];
|
|
156
|
+
}, sources: ForYouSource[]): ForYouCourseMatch | undefined;
|
|
157
|
+
/**
|
|
158
|
+
* Order recommendations so the most direct matches lead, keeping the input
|
|
159
|
+
* order (nearest first, as Algolia returns a geo search) within a depth.
|
|
160
|
+
* Items that match nothing are dropped: they can only be there because the
|
|
161
|
+
* index and the student's sources disagree, and a row with no reason reads
|
|
162
|
+
* as an advert.
|
|
163
|
+
*
|
|
164
|
+
* @param {T[]} items the hits, in the order they came back.
|
|
165
|
+
* @param {(item: T) => {depth: number}|undefined} matchOf how each matched.
|
|
166
|
+
* @return {T[]} the matched items, deepest first.
|
|
167
|
+
*/
|
|
168
|
+
export declare function rankForYou<T>(items: T[], matchOf: (item: T) => {
|
|
169
|
+
depth: number;
|
|
170
|
+
} | undefined): T[];
|
package/lib/pathways.js
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Pathways: the joins between the careers library (SOC 2020), the apprenticeship
|
|
4
|
+
* mirror and the university course mirror, and what a student's own interests
|
|
5
|
+
* mean as a filter over the two.
|
|
6
|
+
*
|
|
7
|
+
* Everything routes through the 4-digit SOC 2020 unit group. Neither mirror
|
|
8
|
+
* carries one directly, so each is one hop away:
|
|
9
|
+
*
|
|
10
|
+
* vacancy.larsCode ─► IfATE standard.occupationCode ─► skillsEngland[].stdCode ─► soc
|
|
11
|
+
* course.commonJobs[i] (a HESA label) ─► SOC 2020 group title ─► prefix ("213")
|
|
12
|
+
*
|
|
13
|
+
* The HESA labels are SOC groups at whatever level HESA chose — mostly minor
|
|
14
|
+
* groups, a few major or unit — so a course links to a *prefix*, and both
|
|
15
|
+
* indexes carry each code's full prefix chain (`socPrefixChain`) so one exact
|
|
16
|
+
* Algolia facet term can match at any level.
|
|
17
|
+
*
|
|
18
|
+
* The functions here are pure and shared: the backend importers use the chain
|
|
19
|
+
* and the label matcher, the web uses the student-side helpers to build the
|
|
20
|
+
* "For you" filter and to say why a row matched.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.socPrefixChain = socPrefixChain;
|
|
24
|
+
exports.normaliseSocGroupTitle = normaliseSocGroupTitle;
|
|
25
|
+
exports.socPrefixForLabel = socPrefixForLabel;
|
|
26
|
+
exports.socCodesForCategory = socCodesForCategory;
|
|
27
|
+
exports.forYouSources = forYouSources;
|
|
28
|
+
exports.forYouFilter = forYouFilter;
|
|
29
|
+
exports.forYouMatch = forYouMatch;
|
|
30
|
+
exports.forYouCourseMatch = forYouCourseMatch;
|
|
31
|
+
exports.rankForYou = rankForYou;
|
|
32
|
+
const lmiCategories_1 = require("./lmiCategories");
|
|
33
|
+
/**
|
|
34
|
+
* A SOC 2020 code's ancestors and itself, shortest first.
|
|
35
|
+
*
|
|
36
|
+
* Accepts a unit group, a sub-unit ("2134/03") or a preference key ("2134-03");
|
|
37
|
+
* only the leading digits count. A code shorter than four digits (a HESA label
|
|
38
|
+
* that resolved to a minor group) yields the chain up to its own length.
|
|
39
|
+
*
|
|
40
|
+
* @param {string} code the SOC 2020 code, any of the forms above.
|
|
41
|
+
* @return {string[]} e.g. ["2", "21", "213", "2134"]; empty for non-SOC input.
|
|
42
|
+
*/
|
|
43
|
+
function socPrefixChain(code) {
|
|
44
|
+
const digits = String(code ?? "").trim().match(/^\d{1,4}/)?.[0] ?? "";
|
|
45
|
+
return Array.from({ length: digits.length }, (_, i) => digits.slice(0, i + 1));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The form HESA labels and ONS group titles are compared in.
|
|
49
|
+
*
|
|
50
|
+
* Case, punctuation and spacing differ between the two sources ("Teaching
|
|
51
|
+
* Professionals" vs "Teaching professionals", "(RandD)" vs "(R&D)"), and one
|
|
52
|
+
* HESA label is singular where ONS is plural. Nothing semantic is done: if a
|
|
53
|
+
* future label needs more than this, it belongs in `unmatched`, not here.
|
|
54
|
+
*
|
|
55
|
+
* @param {string} title a label or group title.
|
|
56
|
+
* @return {string} the comparison key.
|
|
57
|
+
*/
|
|
58
|
+
function normaliseSocGroupTitle(title) {
|
|
59
|
+
return String(title ?? "")
|
|
60
|
+
.toLowerCase()
|
|
61
|
+
.replace(/\(randd\)/g, "(r&d)")
|
|
62
|
+
.replace(/[^a-z0-9 ]/g, "")
|
|
63
|
+
.replace(/\s+/g, " ")
|
|
64
|
+
.trim()
|
|
65
|
+
.replace(/ occupation$/, " occupations");
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The SOC 2020 group a HESA common-job label names.
|
|
69
|
+
*
|
|
70
|
+
* @param {string} label the label as JOBLIST prints it.
|
|
71
|
+
* @param {{[code: string]: string}} titles the SOC hierarchy, code → title.
|
|
72
|
+
* @return {string|undefined} the group code, or undefined for a label no
|
|
73
|
+
* title matches.
|
|
74
|
+
*/
|
|
75
|
+
function socPrefixForLabel(label, titles) {
|
|
76
|
+
const wanted = normaliseSocGroupTitle(label);
|
|
77
|
+
if (!wanted)
|
|
78
|
+
return undefined;
|
|
79
|
+
for (const [code, title] of Object.entries(titles)) {
|
|
80
|
+
if (normaliseSocGroupTitle(title) === wanted)
|
|
81
|
+
return code;
|
|
82
|
+
}
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The 3-digit minor groups an interest category covers, plus any unit groups
|
|
87
|
+
* filed under it by override. Sorted, so a filter built from it is stable.
|
|
88
|
+
*
|
|
89
|
+
* @param {string} category one of CAREER_LIBRARY_CATEGORIES.
|
|
90
|
+
* @return {string[]} the codes; empty for an unknown category.
|
|
91
|
+
*/
|
|
92
|
+
function socCodesForCategory(category) {
|
|
93
|
+
const codes = new Set();
|
|
94
|
+
for (const [minor, c] of Object.entries(lmiCategories_1.CAREER_CATEGORY_BY_SOC_MINOR)) {
|
|
95
|
+
if (c === category)
|
|
96
|
+
codes.add(minor);
|
|
97
|
+
}
|
|
98
|
+
for (const [unit, c] of Object.entries(lmiCategories_1.CAREER_CATEGORY_BY_SOC_UNIT)) {
|
|
99
|
+
if (c === category && !codes.has(unit.slice(0, 3)))
|
|
100
|
+
codes.add(unit);
|
|
101
|
+
}
|
|
102
|
+
return [...codes].sort();
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* What a student's careers tab says they are interested in, as filter sources.
|
|
106
|
+
*
|
|
107
|
+
* Hearted jobs first (exact unit groups), then interest categories (sets of
|
|
108
|
+
* minor groups), in the order the student holds them. The categories are the
|
|
109
|
+
* live set if they have edited it, otherwise their latest survey answer — the
|
|
110
|
+
* same rule the library sidebar shows them under.
|
|
111
|
+
*
|
|
112
|
+
* @param {Pick<UserData, "currentJobPreferences"|"currentCareerInterests"|"aspirationHistory">} user the student.
|
|
113
|
+
* @return {ForYouSource[]} possibly empty, in which case there is nothing to recommend from.
|
|
114
|
+
*/
|
|
115
|
+
function forYouSources(user) {
|
|
116
|
+
const sources = [];
|
|
117
|
+
const prefs = user?.currentJobPreferences ?? {};
|
|
118
|
+
Object.entries(prefs)
|
|
119
|
+
.sort(([, a], [, b]) => (a.added || "").localeCompare(b.added || ""))
|
|
120
|
+
.forEach(([key, p]) => {
|
|
121
|
+
const soc = (p.soc || key.split("-")[0] || "").trim();
|
|
122
|
+
if (!/^\d{4}$/.test(soc))
|
|
123
|
+
return;
|
|
124
|
+
sources.push({ kind: "job", key, title: p.title || soc, codes: [soc] });
|
|
125
|
+
});
|
|
126
|
+
const interests = user?.currentCareerInterests ??
|
|
127
|
+
[...(user?.aspirationHistory ?? [])]
|
|
128
|
+
.sort((a, b) => (b.date || "").localeCompare(a.date || ""))[0]?.careerInterests ??
|
|
129
|
+
[];
|
|
130
|
+
interests
|
|
131
|
+
.filter((c) => lmiCategories_1.CAREER_LIBRARY_CATEGORIES.includes(c))
|
|
132
|
+
.forEach((category) => {
|
|
133
|
+
const codes = socCodesForCategory(category);
|
|
134
|
+
if (codes.length)
|
|
135
|
+
sources.push({ kind: "category", title: category, codes });
|
|
136
|
+
});
|
|
137
|
+
return sources;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Turn the sources into the two term lists, deduped and sorted.
|
|
141
|
+
*
|
|
142
|
+
* @param {ForYouSource[]} sources from `forYouSources`, possibly narrowed to
|
|
143
|
+
* the chips the student tapped.
|
|
144
|
+
* @return {ForYouFilter} empty lists when there are no sources.
|
|
145
|
+
*/
|
|
146
|
+
function forYouFilter(sources) {
|
|
147
|
+
const vacancy = new Set();
|
|
148
|
+
const course = new Set();
|
|
149
|
+
for (const s of sources) {
|
|
150
|
+
for (const code of s.codes) {
|
|
151
|
+
vacancy.add(code);
|
|
152
|
+
socPrefixChain(code).forEach((p) => course.add(p));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
vacancyTerms: [...vacancy].sort(),
|
|
157
|
+
courseTerms: [...course].sort(),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Which source a row is there because of.
|
|
162
|
+
*
|
|
163
|
+
* A row matches a source code when the row sits under the code (a vacancy at
|
|
164
|
+
* 2134 under an interest's 213) or the code sits under the row's own group (a
|
|
165
|
+
* course filed under "213" for a hearted 2134). Sharing an ancestor is not
|
|
166
|
+
* enough — 2211 and 2134 both start with "2" and have nothing to do with each
|
|
167
|
+
* other — so the row side is compared at the ends of its chains, never at
|
|
168
|
+
* an ancestor. The longest such overlap wins, which is what makes a hearted
|
|
169
|
+
* job beat a category covering the same minor group, and the depth comes
|
|
170
|
+
* back so a list can sort exact matches above group-level ones.
|
|
171
|
+
*
|
|
172
|
+
* @param {string[]} rowPrefixes the record's `socPrefixes`.
|
|
173
|
+
* @param {ForYouSource[]} sources the sources the filter was built from.
|
|
174
|
+
* @return {{source: ForYouSource, depth: number}|undefined} the best source,
|
|
175
|
+
* or undefined when nothing overlaps (a row from an unfiltered search).
|
|
176
|
+
*/
|
|
177
|
+
function forYouMatch(rowPrefixes, sources) {
|
|
178
|
+
const rows = new Set(rowPrefixes ?? []);
|
|
179
|
+
// The codes the row is actually filed under: chain ends, not ancestors.
|
|
180
|
+
const leaves = [...rows].filter((p) => ![...rows].some((q) => q.length === p.length + 1 && q.startsWith(p)));
|
|
181
|
+
let best;
|
|
182
|
+
for (const source of sources) {
|
|
183
|
+
for (const code of source.codes) {
|
|
184
|
+
const depth = rows.has(code) ? code.length :
|
|
185
|
+
leaves.filter((leaf) => code.startsWith(leaf))
|
|
186
|
+
.reduce((n, leaf) => Math.max(n, leaf.length), 0);
|
|
187
|
+
if (depth && (!best || depth > best.depth))
|
|
188
|
+
best = { source, depth };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return best;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Which source a course matched, and through which of its common-job groups.
|
|
195
|
+
*
|
|
196
|
+
* The course's `socPrefixes` say whether it matches at all; its
|
|
197
|
+
* `commonJobGroups` say which group did it, and that group's `perc` is the
|
|
198
|
+
* figure a row quotes — "41% went into information technology professionals".
|
|
199
|
+
* Where two groups match, the deeper one wins, then the larger share. A course
|
|
200
|
+
* indexed before the groups existed still matches on its prefixes, just with
|
|
201
|
+
* no group to quote.
|
|
202
|
+
*
|
|
203
|
+
* @param {object} course the index record, or the part of it that matters.
|
|
204
|
+
* @param {string[]} [course.socPrefixes] its prefix chains.
|
|
205
|
+
* @param {HeCommonJobGroup[]} [course.commonJobGroups] its groups.
|
|
206
|
+
* @param {ForYouSource[]} sources the sources the filter was built from.
|
|
207
|
+
* @return {ForYouCourseMatch|undefined} the match, or nothing.
|
|
208
|
+
*/
|
|
209
|
+
function forYouCourseMatch(course, sources) {
|
|
210
|
+
const overall = forYouMatch(course.socPrefixes, sources);
|
|
211
|
+
if (!overall)
|
|
212
|
+
return undefined;
|
|
213
|
+
const best = (course.commonJobGroups ?? [])
|
|
214
|
+
.filter((g) => g.prefix)
|
|
215
|
+
.map((g) => ({ group: g, match: forYouMatch(socPrefixChain(g.prefix), sources) }))
|
|
216
|
+
.filter((x) => Boolean(x.match))
|
|
217
|
+
.sort((a, b) => b.match.depth - a.match.depth ||
|
|
218
|
+
(b.group.perc ?? -1) - (a.group.perc ?? -1))[0];
|
|
219
|
+
return best ?
|
|
220
|
+
{ source: best.match.source, depth: best.match.depth, group: best.group } :
|
|
221
|
+
overall;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Order recommendations so the most direct matches lead, keeping the input
|
|
225
|
+
* order (nearest first, as Algolia returns a geo search) within a depth.
|
|
226
|
+
* Items that match nothing are dropped: they can only be there because the
|
|
227
|
+
* index and the student's sources disagree, and a row with no reason reads
|
|
228
|
+
* as an advert.
|
|
229
|
+
*
|
|
230
|
+
* @param {T[]} items the hits, in the order they came back.
|
|
231
|
+
* @param {(item: T) => {depth: number}|undefined} matchOf how each matched.
|
|
232
|
+
* @return {T[]} the matched items, deepest first.
|
|
233
|
+
*/
|
|
234
|
+
function rankForYou(items, matchOf) {
|
|
235
|
+
return items
|
|
236
|
+
.map((item, index) => ({ item, index, depth: matchOf(item)?.depth ?? 0 }))
|
|
237
|
+
.filter((x) => x.depth > 0)
|
|
238
|
+
.sort((a, b) => b.depth - a.depth || a.index - b.index)
|
|
239
|
+
.map((x) => x.item);
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=pathways.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathways.js","sourceRoot":"","sources":["../src/pathways.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|