@tscircuit/fake-snippets 0.0.40 → 0.0.41
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/bundle.js +2 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +1 -0
- package/fake-snippets-api/lib/db/schema.ts +1 -0
- package/package.json +1 -1
- package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +22 -19
- package/src/components/ViewPackagePage/components/repo-page-content.tsx +0 -3
- package/src/components/ViewPackagePage/components/sidebar-about-section.tsx +34 -15
- package/src/components/ViewPackagePage/components/sidebar.tsx +1 -0
- package/src/components/ViewPackagePage/utils/get-license-content.ts +119 -0
- package/src/components/dialogs/edit-package-details-dialog.tsx +130 -48
- package/src/hooks/use-package-details-form.ts +81 -0
- package/src/lib/getLicenseFromLicenseContent.ts +67 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { useState, useEffect, useMemo } from "react"
|
|
2
|
+
|
|
3
|
+
const isValidUrl = (url: string): boolean => {
|
|
4
|
+
if (!url) return true
|
|
5
|
+
try {
|
|
6
|
+
new URL(url)
|
|
7
|
+
return true
|
|
8
|
+
} catch (e) {
|
|
9
|
+
return false
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface PackageDetailsForm {
|
|
14
|
+
description: string
|
|
15
|
+
website: string
|
|
16
|
+
license: string | null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface UsePackageDetailsFormProps {
|
|
20
|
+
initialDescription: string
|
|
21
|
+
initialWebsite: string
|
|
22
|
+
initialLicense: string | null
|
|
23
|
+
isDialogOpen: boolean
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const usePackageDetailsForm = ({
|
|
27
|
+
initialDescription,
|
|
28
|
+
initialWebsite,
|
|
29
|
+
initialLicense,
|
|
30
|
+
isDialogOpen,
|
|
31
|
+
}: UsePackageDetailsFormProps) => {
|
|
32
|
+
const [formData, setFormData] = useState<PackageDetailsForm>({
|
|
33
|
+
description: initialDescription,
|
|
34
|
+
website: initialWebsite,
|
|
35
|
+
license: initialLicense || null,
|
|
36
|
+
})
|
|
37
|
+
const [websiteError, setWebsiteError] = useState<string | null>(null)
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (isDialogOpen) {
|
|
41
|
+
setFormData({
|
|
42
|
+
description: initialDescription,
|
|
43
|
+
website: initialWebsite,
|
|
44
|
+
license: initialLicense || null,
|
|
45
|
+
})
|
|
46
|
+
setWebsiteError(null)
|
|
47
|
+
}
|
|
48
|
+
}, [isDialogOpen, initialDescription, initialWebsite, initialLicense])
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (formData.website && !isValidUrl(formData.website)) {
|
|
52
|
+
setWebsiteError("Please enter a valid URL (e.g., https://tscircuit.com)")
|
|
53
|
+
} else {
|
|
54
|
+
setWebsiteError(null)
|
|
55
|
+
}
|
|
56
|
+
}, [formData.website])
|
|
57
|
+
|
|
58
|
+
const hasLicenseChanged = useMemo(
|
|
59
|
+
() => formData.license !== initialLicense,
|
|
60
|
+
[formData.license, initialLicense],
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
const hasChanges = useMemo(
|
|
64
|
+
() =>
|
|
65
|
+
formData.description !== initialDescription ||
|
|
66
|
+
formData.website !== initialWebsite ||
|
|
67
|
+
formData.license !== initialLicense,
|
|
68
|
+
[formData, initialDescription, initialWebsite, initialLicense],
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
const isFormValid = useMemo(() => !websiteError, [websiteError])
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
formData,
|
|
75
|
+
setFormData,
|
|
76
|
+
websiteError,
|
|
77
|
+
hasLicenseChanged,
|
|
78
|
+
hasChanges,
|
|
79
|
+
isFormValid,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
type LicenseType = "MIT" | "Apache-2.0" | "BSD-3-Clause" | "GPL-3.0" | "unset"
|
|
2
|
+
|
|
3
|
+
const licenseKeyPhrases = {
|
|
4
|
+
MIT: [
|
|
5
|
+
"mit license",
|
|
6
|
+
"permission is hereby granted, free of charge",
|
|
7
|
+
"without restriction",
|
|
8
|
+
"furnished to do so",
|
|
9
|
+
'the software is provided "as is"',
|
|
10
|
+
"without warranty of any kind",
|
|
11
|
+
"copyright (c)",
|
|
12
|
+
],
|
|
13
|
+
"Apache-2.0": [
|
|
14
|
+
"apache license",
|
|
15
|
+
"version 2.0",
|
|
16
|
+
"licensed under the apache license",
|
|
17
|
+
"http://www.apache.org/licenses/",
|
|
18
|
+
"subject to the following conditions",
|
|
19
|
+
"unless required by applicable law",
|
|
20
|
+
],
|
|
21
|
+
"BSD-3-Clause": [
|
|
22
|
+
"redistribution and use in source and binary forms",
|
|
23
|
+
"redistributions of source code must retain",
|
|
24
|
+
"redistributions in binary form must reproduce",
|
|
25
|
+
"neither the name",
|
|
26
|
+
"nor the names of its contributors may be used",
|
|
27
|
+
],
|
|
28
|
+
"GPL-3.0": [
|
|
29
|
+
"gnu general public license",
|
|
30
|
+
"version 3",
|
|
31
|
+
"free software foundation",
|
|
32
|
+
"either version 3 of the license",
|
|
33
|
+
"everyone is permitted to copy and distribute",
|
|
34
|
+
"gnu general public license for more details",
|
|
35
|
+
],
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Currently using this because latest_license is not fully supported yet
|
|
39
|
+
export const getLicenseFromLicenseContent = (
|
|
40
|
+
licenseContent: string,
|
|
41
|
+
): LicenseType => {
|
|
42
|
+
// Normalize the license content by removing extra whitespace and converting to lowercase
|
|
43
|
+
const normalizedContent = licenseContent
|
|
44
|
+
.toLowerCase()
|
|
45
|
+
.replace(/\s+/g, " ")
|
|
46
|
+
.trim()
|
|
47
|
+
|
|
48
|
+
let bestMatch: { type: LicenseType; ratio: number } = {
|
|
49
|
+
type: "unset",
|
|
50
|
+
ratio: 0,
|
|
51
|
+
}
|
|
52
|
+
const matchThreshold = 0.7
|
|
53
|
+
|
|
54
|
+
// Check each license type
|
|
55
|
+
for (const [licenseType, phrases] of Object.entries(licenseKeyPhrases)) {
|
|
56
|
+
const matchedPhrases = phrases.filter((phrase) =>
|
|
57
|
+
normalizedContent.includes(phrase.toLowerCase()),
|
|
58
|
+
)
|
|
59
|
+
const matchRatio = matchedPhrases.length / phrases.length
|
|
60
|
+
|
|
61
|
+
if (matchRatio >= matchThreshold && matchRatio > bestMatch.ratio) {
|
|
62
|
+
bestMatch = { type: licenseType as LicenseType, ratio: matchRatio }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return bestMatch.type
|
|
67
|
+
}
|