@takuhon/core 0.12.0 → 0.13.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/dist/index.d.ts CHANGED
@@ -3712,6 +3712,95 @@ declare class ConflictError extends StorageError {
3712
3712
  */
3713
3713
  declare function renderActivitySvg(snapshot: ActivitySnapshot): string;
3714
3714
 
3715
+ /**
3716
+ * Résumé / CV projection of a profile.
3717
+ *
3718
+ * {@link deriveCv} turns one locale-resolved {@link LocalizedTakuhon} into a
3719
+ * {@link CvDocument}: a header plus the CV-relevant sections in a fixed,
3720
+ * résumé-conventional order. It is a pure, deterministic selection-and-projection
3721
+ * — no clock, no randomness, no I/O — so the static export ({@link
3722
+ * import('@takuhon/cli')}) and a React `CvView` render identical output from the
3723
+ * same input.
3724
+ *
3725
+ * A CV is a curated *subset* of the profile: the web-page-specific sections
3726
+ * (links, recommendations, the activity dashboard, test scores) are omitted,
3727
+ * and the rest appear in the order a résumé conventionally uses. Entry order
3728
+ * within a section is preserved from the input (already normalized by `order`
3729
+ * upstream), so the owner's `order` field controls it — `deriveCv` never
3730
+ * re-sorts. Empty sections are dropped so the renderer can iterate without
3731
+ * emptiness checks.
3732
+ *
3733
+ * The input must already be privacy-filtered (`applyPublicPrivacyFilter`) by the
3734
+ * caller, exactly as the public render path is: `deriveCv` does not strip
3735
+ * anything itself, it only projects what it is given.
3736
+ */
3737
+
3738
+ /** The header block of a CV: identity and contact, drawn from `profile` + `contact`. */
3739
+ interface CvHeader {
3740
+ displayName: string;
3741
+ tagline?: string;
3742
+ /** Human-readable location (the address `display` string), if present. */
3743
+ location?: string;
3744
+ bio?: string;
3745
+ /** Email, only when the profile exposed it (privacy filter already applied). */
3746
+ email?: string;
3747
+ formUrl?: string;
3748
+ }
3749
+ /**
3750
+ * One CV section, discriminated by `kind`, carrying the locale-resolved entries
3751
+ * for that section. The entry types are reused verbatim from `LocalizedTakuhon`.
3752
+ */
3753
+ type CvSection = {
3754
+ kind: 'experience';
3755
+ entries: LocalizedCareer[];
3756
+ } | {
3757
+ kind: 'education';
3758
+ entries: LocalizedEducation[];
3759
+ } | {
3760
+ kind: 'skills';
3761
+ entries: Skill[];
3762
+ } | {
3763
+ kind: 'certifications';
3764
+ entries: LocalizedCertification[];
3765
+ } | {
3766
+ kind: 'publications';
3767
+ entries: LocalizedPublication[];
3768
+ } | {
3769
+ kind: 'honors';
3770
+ entries: LocalizedHonor[];
3771
+ } | {
3772
+ kind: 'courses';
3773
+ entries: LocalizedCourse[];
3774
+ } | {
3775
+ kind: 'patents';
3776
+ entries: LocalizedPatent[];
3777
+ } | {
3778
+ kind: 'languages';
3779
+ entries: LocalizedLanguage[];
3780
+ } | {
3781
+ kind: 'volunteering';
3782
+ entries: LocalizedVolunteering[];
3783
+ } | {
3784
+ kind: 'memberships';
3785
+ entries: LocalizedMembership[];
3786
+ };
3787
+ /** Every `CvSection` discriminant, in the fixed résumé order `deriveCv` emits. */
3788
+ type CvSectionKind = CvSection['kind'];
3789
+ /** A résumé/CV view derived from a profile: a header plus ordered sections. */
3790
+ interface CvDocument {
3791
+ /** The locale this CV was resolved at (mirrors `LocalizedTakuhon.resolvedLocale`). */
3792
+ resolvedLocale: string;
3793
+ header: CvHeader;
3794
+ /** Non-empty sections only, in the fixed CV order. */
3795
+ sections: CvSection[];
3796
+ }
3797
+ /**
3798
+ * Project a locale-resolved profile into a {@link CvDocument}. Sections appear
3799
+ * in a fixed résumé-conventional order and empty ones are omitted; entry order
3800
+ * within each section is preserved from the input. Pure and deterministic.
3801
+ */
3802
+ declare function deriveCv(localized: LocalizedTakuhon): CvDocument;
3803
+
3715
3804
  /**
3716
3805
  * Image-asset helpers for uploaded media (avatars, project images): magic-byte
3717
3806
  * type detection, header-only dimension / frame reading, and metadata stripping
@@ -3812,4 +3901,4 @@ declare function stripImageMetadata(bytes: Uint8Array, mime: AcceptedImageMime):
3812
3901
  */
3813
3902
  declare const SCHEMA_VERSION = "0.5.0";
3814
3903
 
3815
- export { ACCEPTED_IMAGE_MIME_TYPES, type AcceptedImageMime, type ActivitySettings, type ActivitySnapshot, type ActivityStorage, type Address, type AssetOptions, type AssetRecord, type Avatar, type Career, type Certification, type CodingTime, ConflictError, type Contact, type ContentLicense, type ContentLicenseAttribution, type ContributionCalendar, type ContributionDay, type Course, type Education, type ExportOptions, type ExportedTakuhon, type Honor, IMAGE_EXTENSIONS, type ImageInfo, ImportError, type Iso3166Alpha2, type IsoDateTime, type Language, type LanguageBreakdown, type LanguageProficiency, type Link, type LinkBuiltin, type LinkCustom, type LinkType, type LocaleTag, type LocalizedAddress, type LocalizedAvatar, type LocalizedBody, type LocalizedCareer, type LocalizedCertification, type LocalizedCourse, type LocalizedEducation, type LocalizedHonor, type LocalizedLanguage, type LocalizedLink, type LocalizedLinkBuiltin, type LocalizedLinkCustom, type LocalizedMembership, type LocalizedPatent, type LocalizedProfile, type LocalizedProject, type LocalizedPublication, type LocalizedRecommendation, type LocalizedRecommendationAuthor, type LocalizedTakuhon, type LocalizedTestScore, type LocalizedTitle, type LocalizedVolunteering, MAX_IMAGE_BYTES, MAX_IMAGE_DIMENSION, MAX_IMAGE_FRAMES, type Membership, type Meta, type MetaPrivacy, type Migration, MigrationError, type NormalizedTakuhon, NotFoundError, type Patent, type PatentStatus, type Profile, type Project, type Publication, RANK_FULL_CODING_HOURS, RANK_FULL_CONTRIBUTIONS, RANK_TIER_THRESHOLDS, type RankInput, type RankTier, type RankTierLabel, type Recommendation, type RecommendationAuthor, SCHEMA_VERSION, SUPPORTED_SCHEMA_VERSIONS, type Schema, type Settings, type Skill, type Slug, StorageError, type Takuhon, type TakuhonAssetStorage, type TakuhonStorage, type TestScore, type ValidationError, type ValidationResult, type Volunteering, type YearMonth, applyPublicPrivacyFilter, computeLanguagePercentages, deriveRankTier, detectImageMime, exportTakuhon, formatCodingTime, generateJsonLd, generatePersonJsonLd, generateProfilePageJsonLd, importTakuhon, isActivitySnapshot, migrateTakuhon, migrations, normalize, readImageInfo, renderActivitySvg, resolveLocale, schema, stripImageMetadata, validate };
3904
+ export { ACCEPTED_IMAGE_MIME_TYPES, type AcceptedImageMime, type ActivitySettings, type ActivitySnapshot, type ActivityStorage, type Address, type AssetOptions, type AssetRecord, type Avatar, type Career, type Certification, type CodingTime, ConflictError, type Contact, type ContentLicense, type ContentLicenseAttribution, type ContributionCalendar, type ContributionDay, type Course, type CvDocument, type CvHeader, type CvSection, type CvSectionKind, type Education, type ExportOptions, type ExportedTakuhon, type Honor, IMAGE_EXTENSIONS, type ImageInfo, ImportError, type Iso3166Alpha2, type IsoDateTime, type Language, type LanguageBreakdown, type LanguageProficiency, type Link, type LinkBuiltin, type LinkCustom, type LinkType, type LocaleTag, type LocalizedAddress, type LocalizedAvatar, type LocalizedBody, type LocalizedCareer, type LocalizedCertification, type LocalizedCourse, type LocalizedEducation, type LocalizedHonor, type LocalizedLanguage, type LocalizedLink, type LocalizedLinkBuiltin, type LocalizedLinkCustom, type LocalizedMembership, type LocalizedPatent, type LocalizedProfile, type LocalizedProject, type LocalizedPublication, type LocalizedRecommendation, type LocalizedRecommendationAuthor, type LocalizedTakuhon, type LocalizedTestScore, type LocalizedTitle, type LocalizedVolunteering, MAX_IMAGE_BYTES, MAX_IMAGE_DIMENSION, MAX_IMAGE_FRAMES, type Membership, type Meta, type MetaPrivacy, type Migration, MigrationError, type NormalizedTakuhon, NotFoundError, type Patent, type PatentStatus, type Profile, type Project, type Publication, RANK_FULL_CODING_HOURS, RANK_FULL_CONTRIBUTIONS, RANK_TIER_THRESHOLDS, type RankInput, type RankTier, type RankTierLabel, type Recommendation, type RecommendationAuthor, SCHEMA_VERSION, SUPPORTED_SCHEMA_VERSIONS, type Schema, type Settings, type Skill, type Slug, StorageError, type Takuhon, type TakuhonAssetStorage, type TakuhonStorage, type TestScore, type ValidationError, type ValidationResult, type Volunteering, type YearMonth, applyPublicPrivacyFilter, computeLanguagePercentages, deriveCv, deriveRankTier, detectImageMime, exportTakuhon, formatCodingTime, generateJsonLd, generatePersonJsonLd, generateProfilePageJsonLd, importTakuhon, isActivitySnapshot, migrateTakuhon, migrations, normalize, readImageInfo, renderActivitySvg, resolveLocale, schema, stripImageMetadata, validate };
package/dist/index.js CHANGED
@@ -11558,6 +11558,35 @@ function renderActivitySvg(snapshot) {
11558
11558
  return `<svg xmlns="http://www.w3.org/2000/svg" width="${String(WIDTH)}" height="${String(height)}" viewBox="0 0 ${String(WIDTH)} ${String(height)}" role="img" aria-label="Developer activity"><title>Developer activity</title>${parts.join("")}</svg>`;
11559
11559
  }
11560
11560
 
11561
+ // src/cv.ts
11562
+ function deriveCv(localized) {
11563
+ const p = localized.profile;
11564
+ const header = { displayName: p.displayName };
11565
+ if (p.tagline !== void 0) header.tagline = p.tagline;
11566
+ if (p.location?.display !== void 0) header.location = p.location.display;
11567
+ if (p.bio !== void 0) header.bio = p.bio;
11568
+ if (localized.contact.email !== void 0) header.email = localized.contact.email;
11569
+ if (localized.contact.formUrl !== void 0) header.formUrl = localized.contact.formUrl;
11570
+ const candidates = [
11571
+ { kind: "experience", entries: localized.careers },
11572
+ { kind: "education", entries: localized.education },
11573
+ { kind: "skills", entries: localized.skills },
11574
+ { kind: "certifications", entries: localized.certifications },
11575
+ { kind: "publications", entries: localized.publications },
11576
+ { kind: "honors", entries: localized.honors },
11577
+ { kind: "courses", entries: localized.courses },
11578
+ { kind: "patents", entries: localized.patents },
11579
+ { kind: "languages", entries: localized.languages },
11580
+ { kind: "volunteering", entries: localized.volunteering },
11581
+ { kind: "memberships", entries: localized.memberships }
11582
+ ];
11583
+ return {
11584
+ resolvedLocale: localized.resolvedLocale,
11585
+ header,
11586
+ sections: candidates.filter((section) => section.entries.length > 0)
11587
+ };
11588
+ }
11589
+
11561
11590
  // src/image.ts
11562
11591
  var ACCEPTED_IMAGE_MIME_TYPES = [
11563
11592
  "image/jpeg",
@@ -11908,6 +11937,7 @@ export {
11908
11937
  StorageError,
11909
11938
  applyPublicPrivacyFilter,
11910
11939
  computeLanguagePercentages,
11940
+ deriveCv,
11911
11941
  deriveRankTier,
11912
11942
  detectImageMime,
11913
11943
  exportTakuhon,