mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-06-28 05:52:07 +02:00
Merge branch 'dev' into localization
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
- [#696](https://github.com/estruyf/vscode-front-matter/issues/696): Close the local server terminal on restart
|
||||
- [#699](https://github.com/estruyf/vscode-front-matter/issues/699): Changing border theme variable for the dashboard header
|
||||
- [#703](https://github.com/estruyf/vscode-front-matter/issues/703): Fix retrieval of Astro Collections for `pnpm` projects
|
||||
- [#704](https://github.com/estruyf/vscode-front-matter/issues/704): Fix `zod` schema script for optional fields
|
||||
|
||||
## [9.3.1] - 2023-10-27
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ContentType } from './../models/PanelSettings';
|
||||
export const DEFAULT_CONTENT_TYPE_NAME = 'default';
|
||||
|
||||
export const DEFAULT_CONTENT_TYPE: ContentType = {
|
||||
name: 'default',
|
||||
name: DEFAULT_CONTENT_TYPE_NAME,
|
||||
pageBundle: false,
|
||||
previewPath: null,
|
||||
fields: [
|
||||
|
||||
@@ -4,7 +4,6 @@ import { CheckCircleIcon as CheckCircleIconSolid, PlusCircleIcon as PlusCircleIc
|
||||
|
||||
export interface ISelectItemProps {
|
||||
title: string;
|
||||
icon?: "add" | "select";
|
||||
buttonTitle: string;
|
||||
isSelected: boolean;
|
||||
disabled?: boolean;
|
||||
@@ -13,7 +12,6 @@ export interface ISelectItemProps {
|
||||
|
||||
export const SelectItem: React.FunctionComponent<ISelectItemProps> = ({
|
||||
title,
|
||||
icon = "select",
|
||||
buttonTitle,
|
||||
isSelected,
|
||||
disabled,
|
||||
@@ -30,17 +28,9 @@ export const SelectItem: React.FunctionComponent<ISelectItemProps> = ({
|
||||
disabled={disabled}
|
||||
>
|
||||
{isSelected ? (
|
||||
icon === "add" ? (
|
||||
<PlusCircleIconSolid className={`h-4 w-4`} />
|
||||
) : (
|
||||
<CheckCircleIconSolid className={`h-4 w-4`} />
|
||||
)
|
||||
<CheckCircleIconSolid className={`h-4 w-4`} />
|
||||
) : (
|
||||
icon === "add" ? (
|
||||
<PlusCircleIcon className={`h-4 w-4`} />
|
||||
) : (
|
||||
<CheckCircleIcon className={`h-4 w-4`} />
|
||||
)
|
||||
<PlusCircleIcon className={`h-4 w-4`} />
|
||||
)}
|
||||
<span>{title}</span>
|
||||
</button>
|
||||
|
||||
@@ -5,7 +5,11 @@ import { BaseListener } from './BaseListener';
|
||||
import { exec } from 'child_process';
|
||||
import { Extension, Logger, Settings } from '../../helpers';
|
||||
import { Folders } from '../../commands';
|
||||
import { SETTING_TAXONOMY_CONTENT_TYPES, SsgScripts } from '../../constants';
|
||||
import {
|
||||
DEFAULT_CONTENT_TYPE_NAME,
|
||||
SETTING_TAXONOMY_CONTENT_TYPES,
|
||||
SsgScripts
|
||||
} from '../../constants';
|
||||
import { SettingsListener } from './SettingsListener';
|
||||
import { Terminal } from '../../services';
|
||||
import { existsAsync, readFileAsync } from '../../utils';
|
||||
@@ -58,7 +62,10 @@ export class SsgListener extends BaseListener {
|
||||
}
|
||||
}
|
||||
|
||||
const contentTypes = Settings.get<ContentType[]>(SETTING_TAXONOMY_CONTENT_TYPES) || [];
|
||||
let contentTypes = Settings.get<ContentType[]>(SETTING_TAXONOMY_CONTENT_TYPES) || [];
|
||||
|
||||
// Filter out the default content type
|
||||
contentTypes = contentTypes.filter((ct) => ct.name !== DEFAULT_CONTENT_TYPE_NAME);
|
||||
|
||||
if (contentTypes.find((ct) => ct.name === collection.name)) {
|
||||
SsgListener.sendRequest(command as any, requestId, {});
|
||||
@@ -150,7 +157,7 @@ export class SsgListener extends BaseListener {
|
||||
|
||||
// Update the vite reference, as it is not a direct dependency of the project
|
||||
let scriptContents = await readFileAsync(scriptPath.fsPath, 'utf8');
|
||||
scriptContents = scriptContents.replace(`"vite"`, `"${vitePath}"`);
|
||||
scriptContents = scriptContents.replace(`'vite'`, `'${vitePath}'`);
|
||||
await workspace.fs.writeFile(tempScriptPath, Buffer.from(scriptContents, 'utf8'));
|
||||
}
|
||||
} else {
|
||||
@@ -209,16 +216,35 @@ export class SsgListener extends BaseListener {
|
||||
} as Field;
|
||||
break;
|
||||
case 'ZodBoolean':
|
||||
ctField = {
|
||||
name: field.name,
|
||||
type: 'boolean'
|
||||
} as Field;
|
||||
if (field.name === 'published') {
|
||||
ctField = {
|
||||
name: field.name,
|
||||
type: 'draft'
|
||||
} as Field;
|
||||
} else {
|
||||
ctField = {
|
||||
name: field.name,
|
||||
type: 'boolean'
|
||||
} as Field;
|
||||
}
|
||||
break;
|
||||
case 'ZodArray':
|
||||
ctField = {
|
||||
name: field.name,
|
||||
type: 'list'
|
||||
} as Field;
|
||||
if (field.name === 'tags') {
|
||||
ctField = {
|
||||
name: field.name,
|
||||
type: 'tags'
|
||||
} as Field;
|
||||
} else if (field.name === 'categories') {
|
||||
ctField = {
|
||||
name: field.name,
|
||||
type: 'categories'
|
||||
} as Field;
|
||||
} else {
|
||||
ctField = {
|
||||
name: field.name,
|
||||
type: 'list'
|
||||
} as Field;
|
||||
}
|
||||
break;
|
||||
case 'ZodEnum':
|
||||
ctField = {
|
||||
@@ -227,6 +253,7 @@ export class SsgListener extends BaseListener {
|
||||
choices: field.options || []
|
||||
} as Field;
|
||||
break;
|
||||
case 'datetime':
|
||||
case 'ZodDate':
|
||||
ctField = {
|
||||
name: field.name,
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface AstroField {
|
||||
| 'ZodEnum'
|
||||
| 'ZodDate'
|
||||
| 'ZodObject'
|
||||
| 'datetime'
|
||||
| 'email'
|
||||
| 'url'
|
||||
| 'image';
|
||||
|
||||
@@ -1,32 +1,35 @@
|
||||
import { writeFileSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { createServer } from "vite";
|
||||
import zod from "astro/zod";
|
||||
import { writeFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { createServer } from 'vite';
|
||||
import zod from 'astro/zod';
|
||||
|
||||
const {
|
||||
ZodDefault,
|
||||
ZodObject,
|
||||
ZodOptional,
|
||||
ZodString,
|
||||
ZodEffects,
|
||||
ZodEnum
|
||||
} = zod;
|
||||
const { ZodDefault, ZodObject, ZodOptional, ZodString, ZodEffects, ZodEnum, ZodUnion } = zod;
|
||||
|
||||
/**
|
||||
* Process the Zod field
|
||||
* @param {ZodTypeAny} field
|
||||
* @param {string} defaultValue
|
||||
* @returns
|
||||
* @param {ZodTypeAny} field
|
||||
* @param {boolean} isOptional
|
||||
* @param {string} defaultValue
|
||||
* @returns
|
||||
*/
|
||||
function getField(field, defaultValue = undefined) {
|
||||
let isOptional = false;
|
||||
|
||||
function getField(field, isOptional = false, defaultValue = undefined) {
|
||||
// Handle various type transformations and assignments
|
||||
if (field instanceof ZodOptional) {
|
||||
isOptional = true;
|
||||
const type = field.unwrap();
|
||||
|
||||
return getField(type, isOptional, defaultValue)
|
||||
return getField(type, isOptional, defaultValue);
|
||||
}
|
||||
|
||||
if (field instanceof ZodEffects) {
|
||||
const type = field.sourceType();
|
||||
return getField(type, isOptional, defaultValue);
|
||||
}
|
||||
|
||||
if (field instanceof ZodUnion) {
|
||||
const types = field._def.options;
|
||||
const type = types[0];
|
||||
return getField(type, isOptional, defaultValue);
|
||||
}
|
||||
|
||||
if (field instanceof ZodDefault) {
|
||||
@@ -35,43 +38,43 @@ function getField(field, defaultValue = undefined) {
|
||||
defaultValue = field.parse(undefined);
|
||||
// https://github.com/sachinraja/zod-to-ts/blob/main/src/index.ts
|
||||
const type = field._def.innerType;
|
||||
return getField(type, isOptional, defaultValue)
|
||||
return getField(type, isOptional, defaultValue);
|
||||
}
|
||||
|
||||
return {
|
||||
type: field,
|
||||
isOptional,
|
||||
defaultValue
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the field information
|
||||
* @param {string} name
|
||||
* @param {ZodTypeAny} type
|
||||
* @returns
|
||||
* @param {string} name
|
||||
* @param {ZodTypeAny} type
|
||||
* @returns
|
||||
*/
|
||||
function generateFieldInfo(name, type) {
|
||||
let description = type.description;
|
||||
let defaultValue = undefined;
|
||||
|
||||
const {
|
||||
type: fieldType,
|
||||
isOptional: isFieldOptional,
|
||||
defaultValue: fieldDefaultValue
|
||||
} = getField(type, defaultValue);
|
||||
const {
|
||||
type: fieldType,
|
||||
isOptional: isFieldOptional,
|
||||
defaultValue: fieldDefaultValue
|
||||
} = getField(type, false, defaultValue);
|
||||
|
||||
const fieldInfo = {
|
||||
name: name,
|
||||
description: description,
|
||||
defaultValue: fieldDefaultValue,
|
||||
type: fieldType._def.typeName,
|
||||
required: !isFieldOptional,
|
||||
required: !isFieldOptional
|
||||
};
|
||||
|
||||
if (fieldType instanceof ZodObject) {
|
||||
const subFields = extractFieldInfoFromShape(fieldType);
|
||||
|
||||
|
||||
fieldInfo.fields = subFields;
|
||||
}
|
||||
|
||||
@@ -79,6 +82,10 @@ function generateFieldInfo(name, type) {
|
||||
fieldInfo.type = fieldType.sourceType().fmFieldType;
|
||||
}
|
||||
|
||||
if (fieldInfo.name.toLowerCase().includes('image')) {
|
||||
fieldInfo.type = 'image';
|
||||
}
|
||||
|
||||
if (fieldType instanceof ZodEnum) {
|
||||
fieldInfo.options = fieldType.options;
|
||||
}
|
||||
@@ -96,8 +103,8 @@ function generateFieldInfo(name, type) {
|
||||
|
||||
/**
|
||||
* Parse the scheme into an array of fields
|
||||
* @param {ZodTypeAny} type
|
||||
* @returns
|
||||
* @param {ZodTypeAny} type
|
||||
* @returns
|
||||
*/
|
||||
function extractFieldInfoFromShape(type) {
|
||||
if (type instanceof ZodOptional) {
|
||||
@@ -106,7 +113,7 @@ function extractFieldInfoFromShape(type) {
|
||||
|
||||
if (!(type instanceof ZodObject)) {
|
||||
// Return an empty array if the type is not of the expected type
|
||||
return [];
|
||||
return [];
|
||||
}
|
||||
|
||||
// Iterate through the shape properties
|
||||
@@ -121,8 +128,8 @@ function extractFieldInfoFromShape(type) {
|
||||
|
||||
/**
|
||||
* Process each content collection
|
||||
* @param {*} collections
|
||||
* @returns
|
||||
* @param {*} collections
|
||||
* @returns
|
||||
*/
|
||||
function processCollection(collections) {
|
||||
if (!Array.isArray(collections)) {
|
||||
@@ -130,32 +137,35 @@ function processCollection(collections) {
|
||||
}
|
||||
|
||||
return collections.map(([name, collection]) => {
|
||||
const schema = typeof collection.schema === "function" ? collection.schema({
|
||||
image() {
|
||||
const field = zod.string();
|
||||
field.fmFieldType = "image";
|
||||
return field;
|
||||
}
|
||||
}) : collection.schema;
|
||||
const schema =
|
||||
typeof collection.schema === 'function'
|
||||
? collection.schema({
|
||||
image() {
|
||||
const field = zod.string();
|
||||
field.fmFieldType = 'image';
|
||||
return field;
|
||||
}
|
||||
})
|
||||
: collection.schema;
|
||||
|
||||
return {
|
||||
name,
|
||||
type: collection.type || "content",
|
||||
fields: extractFieldInfoFromShape(schema),
|
||||
type: collection.type || 'content',
|
||||
fields: extractFieldInfoFromShape(schema)
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* More info: https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
const astroContentModulePlugin = () => {
|
||||
const astroContent = "astro:content";
|
||||
const astroContent = 'astro:content';
|
||||
const astroContentMarker = `\0${astroContent}`;
|
||||
|
||||
return {
|
||||
name: "astro-content-collections",
|
||||
name: 'astro-content-collections',
|
||||
resolveId(importee) {
|
||||
if (importee === astroContent) {
|
||||
return astroContentMarker;
|
||||
@@ -174,7 +184,7 @@ const astroContentModulePlugin = () => {
|
||||
`;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -182,8 +192,8 @@ const astroContentModulePlugin = () => {
|
||||
*/
|
||||
(async () => {
|
||||
const configPath = process.argv[2];
|
||||
if (!configPath || typeof configPath !== "string") {
|
||||
console.log("No config path provided");
|
||||
if (!configPath || typeof configPath !== 'string') {
|
||||
console.log('No config path provided');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -195,22 +205,25 @@ const astroContentModulePlugin = () => {
|
||||
hmr: false
|
||||
},
|
||||
optimizeDeps: {
|
||||
disabled: true,
|
||||
disabled: true
|
||||
},
|
||||
appType: "custom",
|
||||
appType: 'custom',
|
||||
plugins: [astroContentModulePlugin()]
|
||||
});
|
||||
|
||||
try {
|
||||
// https://github.dev/withastro/astro/blob/defab70cb2a0c67d5e9153542490d2749046b151/packages/astro/src/content/utils.ts#L334
|
||||
const contentModule = await server.ssrLoadModule(configPath)
|
||||
const contentModule = await server.ssrLoadModule(configPath);
|
||||
|
||||
const collections = Object.entries(contentModule.collections ?? {});
|
||||
const processedCollections = processCollection(collections);
|
||||
|
||||
writeFileSync(join(process.cwd(), `./.frontmatter/temp/astro.collections.json`), JSON.stringify(processedCollections));
|
||||
|
||||
console.log("Collections generated successfully");
|
||||
writeFileSync(
|
||||
join(process.cwd(), `./.frontmatter/temp/astro.collections.json`),
|
||||
JSON.stringify(processedCollections, null, 2)
|
||||
);
|
||||
|
||||
console.log('Collections generated successfully');
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.log(error.message);
|
||||
@@ -218,4 +231,4 @@ const astroContentModulePlugin = () => {
|
||||
} finally {
|
||||
await server.close();
|
||||
}
|
||||
})();
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user