@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.
@@ -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
+ }