Skip to content

Commit 3a0543f

Browse files
committed
1826-add a warning and info for license changes. Added support for TR language too.
1 parent fbf01bd commit 3a0543f

File tree

6 files changed

+571
-285
lines changed

6 files changed

+571
-285
lines changed

app/components/LicenseDisplay.vue

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,36 @@
11
<script setup lang="ts">
2-
import { parseLicenseExpression } from '#shared/utils/spdx'
2+
import { parseLicenseExpression } from "#shared/utils/spdx";
3+
4+
import { useLicenseChanges } from "~/composables/useLicenseChanges";
5+
import { useI18n } from "vue-i18n";
36
47
const props = defineProps<{
5-
license: string
6-
}>()
8+
license: string;
9+
packageName?: string;
10+
}>();
11+
12+
const { t } = useI18n();
13+
14+
const tokens = computed(() => parseLicenseExpression(props.license));
15+
const licenseChanges = useLicenseChanges(() => props.packageName);
716
8-
const tokens = computed(() => parseLicenseExpression(props.license))
17+
const changes = computed(() => licenseChanges.data.value?.changes ?? []);
918
10-
const hasAnyValidLicense = computed(() => tokens.value.some(t => t.type === 'license' && t.url))
19+
const licenseChangeText = computed(() =>
20+
changes.value
21+
.map((item) =>
22+
t("package.versions.license_change_item", {
23+
from: item.from,
24+
to: item.to,
25+
version: item.version,
26+
}),
27+
)
28+
.join("; "),
29+
);
30+
31+
const hasAnyValidLicense = computed(() =>
32+
tokens.value.some((t) => t.type === "license" && t.url),
33+
);
1134
</script>
1235

1336
<template>
@@ -21,15 +44,42 @@ const hasAnyValidLicense = computed(() => tokens.value.some(t => t.type === 'lic
2144
class="link-subtle"
2245
:title="$t('package.license.view_spdx')"
2346
>
24-
{{ token.value }}
47+
{{ token.value }}!!
2548
</a>
2649
<span v-else-if="token.type === 'license'">{{ token.value }}</span>
27-
<span v-else-if="token.type === 'operator'" class="text-4xs">{{ token.value }}</span>
50+
<span v-else-if="token.type === 'operator'" class="text-4xs">{{
51+
token.value
52+
}}</span>
2853
</template>
2954
<span
3055
v-if="hasAnyValidLicense"
3156
class="i-lucide:scale w-3.5 h-3.5 text-fg-subtle flex-shrink-0 self-center"
3257
aria-hidden="true"
3358
/>
3459
</span>
60+
<div
61+
v-if="changes.length > 0"
62+
class="text-red-500 flex justify-start items-center gap-x-1"
63+
>
64+
<p>change!</p>
65+
<TooltipApp interactive position="top">
66+
<span
67+
tabindex="0"
68+
class="block cursor-help shrink-0 -m-2 p-2 -me-1 focus-visible:outline-2 focus-visible:outline-accent/70 rounded"
69+
>
70+
<span
71+
class="block i-lucide:info w-3.5 h-3.5 text-fg-subtle"
72+
role="img"
73+
:aria-label="$t('package.versions.license_change_help')"
74+
/>
75+
</span>
76+
<template #content>
77+
<p class="text-xs text-fg-muted">
78+
<i18n-t keypath="package.versions.changed_license" tag="span">
79+
<template #license_change>{{ licenseChangeText }}</template>
80+
</i18n-t>
81+
</p>
82+
</template>
83+
</TooltipApp>
84+
</div>
3585
</template>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import type { MaybeRefOrGetter } from 'vue'
2+
import { toValue } from 'vue'
3+
4+
export interface LicenseChange {
5+
from: string
6+
to: string
7+
version: string
8+
}
9+
10+
export interface LicenseChangesResult {
11+
changes: LicenseChange[]
12+
}
13+
14+
// Type definitions for npm registry response
15+
interface NpmRegistryVersion {
16+
version: string
17+
license?: string
18+
}
19+
20+
// for registry responses of $fetch function, the type includes the key versions as well as many others too.
21+
interface NpmRegistryResponse {
22+
versions: Record<
23+
string,
24+
{
25+
version: string
26+
license?: string
27+
}
28+
>
29+
}
30+
31+
/**
32+
* Composable to detect license changes across all versions of a package
33+
*/
34+
export function useLicenseChanges(packageName: MaybeRefOrGetter<string | null | undefined>) {
35+
return useAsyncData<LicenseChangesResult>(
36+
() => `license-changes:${toValue(packageName)}`,
37+
async () => {
38+
const name = toValue(packageName)
39+
if (!name) return { changes: [] }
40+
41+
// Fetch full package metadata from npm registry
42+
const url = `https://registry.npmjs.org/${name}`
43+
const data = await $fetch<NpmRegistryResponse>(url)
44+
45+
const changes: LicenseChange[] = []
46+
let prevLicense: string | undefined = undefined
47+
48+
// `data.versions` is an object with version keys
49+
const versions = Object.values(data.versions) as NpmRegistryVersion[]
50+
51+
// Sort versions ascending to compare chronologically
52+
versions.sort((a, b) => {
53+
const parse = (v: string) => v.split('.').map(Number)
54+
const [aMajor, aMinor, aPatch] = parse(a.version as string)
55+
const [bMajor, bMinor, bPatch] = parse(b.version as string)
56+
if (aMajor !== bMajor) return aMajor! - bMajor!
57+
if (aMinor !== bMinor) return aMinor! - bMinor!
58+
return aPatch! - bPatch!
59+
})
60+
61+
// Detect license changes
62+
for (const version of versions) {
63+
const license = (version.license as string) ?? 'UNKNOWN'
64+
if (prevLicense && license !== prevLicense) {
65+
changes.push({
66+
from: prevLicense,
67+
to: license,
68+
version: version.version as string,
69+
})
70+
}
71+
prevLicense = license
72+
}
73+
return { changes }
74+
},
75+
{
76+
default: () => ({ changes: [] }),
77+
watch: [() => toValue(packageName)],
78+
},
79+
)
80+
}

0 commit comments

Comments
 (0)