mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-08-06 08:52:47 +02:00
init: sync with dev
This commit is contained in:
@@ -24,7 +24,7 @@ jobs:
|
||||
run: node scripts/beta-release.js $GITHUB_RUN_ID
|
||||
|
||||
- name: Publish
|
||||
run: npx vsce publish -p ${{ secrets.VSCE_PAT }} --baseImagesUrl https://raw.githubusercontent.com/estruyf/vscode-front-matter/dev
|
||||
run: npx @vscode/vsce publish -p ${{ secrets.VSCE_PAT }} --baseImagesUrl https://raw.githubusercontent.com/estruyf/vscode-front-matter/dev
|
||||
|
||||
- name: Publish to open-vsx.org
|
||||
run: npx ovsx publish -p ${{ secrets.OPEN_VSX_PAT }}
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
run: node scripts/main-release.js
|
||||
|
||||
- name: Publish
|
||||
run: npx vsce publish -p ${{ secrets.VSCE_PAT }}
|
||||
run: npx @vscode/vsce publish -p ${{ secrets.VSCE_PAT }}
|
||||
|
||||
- name: Publish to open-vsx.org
|
||||
run: npx ovsx publish -p ${{ secrets.OPEN_VSX_PAT }}
|
||||
@@ -1,5 +1,27 @@
|
||||
# Change Log
|
||||
|
||||
## [8.3.0] - 2022-xx-xx
|
||||
|
||||
### ✨ New features
|
||||
|
||||
- [#407](https://github.com/estruyf/vscode-front-matter/issues/407): External config support
|
||||
|
||||
### 🎨 Enhancements
|
||||
|
||||
- [#474](https://github.com/estruyf/vscode-front-matter/issues/474): Allow to define the file prefix on content types
|
||||
- [#484](https://github.com/estruyf/vscode-front-matter/issues/484): Support for overriding scripts per environment type
|
||||
- [#494](https://github.com/estruyf/vscode-front-matter/issues/494): Support for external image URLs in previews
|
||||
- [#497](https://github.com/estruyf/vscode-front-matter/issues/497): Support for movie media previews in the content dashboard
|
||||
|
||||
### ⚡️ Optimizations
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- [#469](https://github.com/estruyf/vscode-front-matter/issues/469): Fix for using the root folder as content folder
|
||||
- [#470](https://github.com/estruyf/vscode-front-matter/issues/470): Fix `initialize project` dashboard description
|
||||
- [#482](https://github.com/estruyf/vscode-front-matter/issues/482): Update the description when you want to overwrite the default content type description
|
||||
- [#493](https://github.com/estruyf/vscode-front-matter/issues/493): Fix an issue where a custom placeholder value is replaced by an `array` instead of a `string`
|
||||
|
||||
## [8.2.0] - 2022-12-08 - [Release notes](https://beta.frontmatter.codes/updates/v8.2.0)
|
||||
|
||||
### ✨ New features
|
||||
|
||||
+3
-3
@@ -10,12 +10,12 @@
|
||||
|
||||
<p align="center">
|
||||
<a href="https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter" title="Check it out on the Visual Studio Marketplace">
|
||||
<img src="https://vsmarketplacebadge.apphb.com/version/eliostruyf.vscode-front-matter.svg" alt="Visual Studio Marketplace" style="display: inline-block" />
|
||||
<img src="https://vsmarketplacebadges.dev/version/eliostruyf.vscode-front-matter.svg" alt="Visual Studio Marketplace" style="display: inline-block" />
|
||||
</a>
|
||||
|
||||
<img src="https://vsmarketplacebadge.apphb.com/installs/eliostruyf.vscode-front-matter.svg" alt="Number of installs" style="display: inline-block;margin-left:10px" />
|
||||
<img src="https://vsmarketplacebadges.dev/installs/eliostruyf.vscode-front-matter.svg" alt="Number of installs" style="display: inline-block;margin-left:10px" />
|
||||
|
||||
<img src="https://vsmarketplacebadge.apphb.com/rating/eliostruyf.vscode-front-matter.svg" alt="Ratings" style="display: inline-block;margin-left:10px" />
|
||||
<img src="https://vsmarketplacebadges.dev/rating/eliostruyf.vscode-front-matter.svg" alt="Ratings" style="display: inline-block;margin-left:10px" />
|
||||
|
||||
<a href="https://github.com/sponsors/estruyf" title="Become a sponsor" style="margin-left:10px">
|
||||
<img src="https://img.shields.io/github/sponsors/estruyf?color=%23CE2E7C&logo=github&style=flat" alt="Sponsor the project" style="display: inline-block" />
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
<p align="center">
|
||||
<a href="https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter" title="Check it out on the Visual Studio Marketplace">
|
||||
<img src="https://vsmarketplacebadge.apphb.com/version/eliostruyf.vscode-front-matter.svg" alt="Visual Studio Marketplace" style="display: inline-block" />
|
||||
<img src="https://vsmarketplacebadges.dev/version/eliostruyf.vscode-front-matter.svg" alt="Visual Studio Marketplace" style="display: inline-block" />
|
||||
</a>
|
||||
|
||||
<img src="https://vsmarketplacebadge.apphb.com/installs/eliostruyf.vscode-front-matter.svg" alt="Number of installs" style="display: inline-block;margin-left:10px" />
|
||||
<img src="https://vsmarketplacebadges.dev/installs/eliostruyf.vscode-front-matter.svg" alt="Number of installs" style="display: inline-block;margin-left:10px" />
|
||||
|
||||
<img src="https://vsmarketplacebadge.apphb.com/rating/eliostruyf.vscode-front-matter.svg" alt="Ratings" style="display: inline-block;margin-left:10px" />
|
||||
<img src="https://vsmarketplacebadges.dev/rating/eliostruyf.vscode-front-matter.svg" alt="Ratings" style="display: inline-block;margin-left:10px" />
|
||||
|
||||
<a href="https://github.com/sponsors/estruyf" title="Become a sponsor" style="margin-left:10px">
|
||||
<img src="https://img.shields.io/github/sponsors/estruyf?color=%23CE2E7C&logo=github&style=flat" alt="Sponsor the project" style="display: inline-block" />
|
||||
@@ -163,21 +163,29 @@ You can open showcase issues for the following things:
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/estruyf/vscode-front-matter/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=estruyf/vscode-front-matter" />
|
||||
<img src="https://contrib.rocks/image?repo=estruyf/vscode-front-matter" alt="Front Matter contributors" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## 🖤 Backers & Sponsors 👇 🤘
|
||||
|
||||
<p align="center">
|
||||
<img src="https://frontmatter.codes/api/img-sponsors" />
|
||||
<img src="https://frontmatter.codes/api/img-sponsors" alt="Front Matter sponsors" />
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
<p align="center" title="Powered by Vercel">
|
||||
<a href="https://vercel.com/?utm_source=vscode-frontmatter&utm_campaign=oss">
|
||||
<img src="https://frontmatter.codes/assets/sponsors/powered-by-vercel.png" alt="Powered by Vercel" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
<p align="center">
|
||||
<a href="https://vercel.com/?utm_source=vscode-frontmatter&utm_campaign=oss">
|
||||
<img src="https://frontmatter.codes/assets/sponsors/powered-by-vercel.png" />
|
||||
<a href="http://bejs.io/" title="Supported by the BEJS Community">
|
||||
<img src="https://frontmatter.codes/assets/sponsors/bejs-community.png" alt="Supported by the BEJS Community" height="50px"/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -190,6 +198,6 @@ You can open showcase issues for the following things:
|
||||
|
||||
<p align="center">
|
||||
<a href="https://visitorbadge.io">
|
||||
<img src="https://api.visitorbadge.io/api/VisitorHit?user=estruyf&repo=vscode-front-matter&countColor=%23F05450&labelColor=%230E131F" height="25px" />
|
||||
<img src="https://api.visitorbadge.io/api/VisitorHit?user=estruyf&repo=vscode-front-matter&countColor=%23F05450&labelColor=%230E131F" height="25px" alt="Front Matter visitors" />
|
||||
</a>
|
||||
</p>
|
||||
+40
-1
@@ -3,7 +3,7 @@
|
||||
"displayName": "Front Matter CMS",
|
||||
"description": "Front Matter is a CMS that runs within Visual Studio Code. It gives you the power and control of a full-blown CMS while also providing you the flexibility and speed of the static site generator of your choice like: Hugo, Jekyll, Docusaurus, NextJs, Gatsby, and many more...",
|
||||
"icon": "assets/frontmatter-teal-128x128.png",
|
||||
"version": "8.2.0",
|
||||
"version": "8.3.0",
|
||||
"preview": false,
|
||||
"publisher": "eliostruyf",
|
||||
"galleryBanner": {
|
||||
@@ -79,6 +79,14 @@
|
||||
"configuration": {
|
||||
"title": "Front Matter: use frontmatter.json for shared team settings",
|
||||
"properties": {
|
||||
"frontMatter.extends": {
|
||||
"type": "array",
|
||||
"markdownDescription": "Specify the list of paths/URLs to extend the Front Matter CMS config. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.extends)",
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"frontMatter.content.autoUpdateDate": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
@@ -454,6 +462,30 @@
|
||||
"type": "boolean",
|
||||
"description": "Hide the action from the UI",
|
||||
"default": false
|
||||
},
|
||||
"environments": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"macos",
|
||||
"linux",
|
||||
"windows"
|
||||
],
|
||||
"description": "The environment type for which the script needs to be used"
|
||||
},
|
||||
"script": {
|
||||
"type": "string",
|
||||
"description": "Path to the script to execute"
|
||||
},
|
||||
"command": {
|
||||
"$ref": "#scriptCommand"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@@ -1260,6 +1292,13 @@
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "An optional post script that can be used after new content creation."
|
||||
},
|
||||
"filePrefix": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
],
|
||||
"description": "Defines a prefix for the file name."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
const packageJson = require('../package.json');
|
||||
|
||||
for (const key of Object.keys(packageJson.contributes.configuration.properties)) {
|
||||
const type = packageJson.contributes.configuration.properties[key].type;
|
||||
|
||||
if (type.includes('object') || type.includes('array')) {
|
||||
console.log(`${key} - ${packageJson.contributes.configuration.properties[key].type}`);
|
||||
}
|
||||
}
|
||||
|
||||
// TO IGNORE
|
||||
// frontMatter.extends - array
|
||||
// frontMatter.dashboard.mediaSnippet - array
|
||||
|
||||
// TO PROCESS AS A WHOLE OBJECT
|
||||
// frontMatter.content.draftField - object
|
||||
// frontMatter.content.supportedFileTypes - array
|
||||
// frontMatter.global.notifications - array
|
||||
// frontMatter.global.disabledNotificaitons - array
|
||||
// frontMatter.media.supportedMimeTypes - array
|
||||
// frontMatter.taxonomy.commaSeparatedFields - array
|
||||
|
||||
// MERGE ARRAYS
|
||||
// frontMatter.taxonomy.categories - array
|
||||
// frontMatter.taxonomy.tags - array
|
||||
// frontMatter.taxonomy.noPropertyValueQuotes - array
|
||||
|
||||
// PROCESS ITEM BY ITEM
|
||||
// frontMatter.custom.scripts - array - id
|
||||
// frontMatter.taxonomy.contentTypes - array,null - name
|
||||
// frontMatter.data.files - array - id
|
||||
// frontMatter.data.folders - array - id
|
||||
// frontMatter.data.types - array - id
|
||||
// frontMatter.content.pageFolders - array - path
|
||||
// frontMatter.content.placeholders - array - id
|
||||
// frontMatter.content.sorting - array - id
|
||||
// frontMatter.global.modes - array - id
|
||||
// frontMatter.taxonomy.fieldGroups - array - id
|
||||
// frontMatter.taxonomy.customTaxonomy - array - id
|
||||
|
||||
|
||||
|
||||
// frontMatter.content.snippets - object
|
||||
@@ -198,7 +198,6 @@ export class Article {
|
||||
Telemetry.send(TelemetryEvent.generateSlug);
|
||||
|
||||
const updateFileName = Settings.get(SETTING_SLUG_UPDATE_FILE_NAME) as string;
|
||||
let filePrefix = Settings.get<string>(SETTING_TEMPLATES_PREFIX);
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
|
||||
if (!editor) {
|
||||
@@ -210,13 +209,10 @@ export class Article {
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the file prefix from the folder
|
||||
const filePrefixOnFolder = Folders.getFilePrefixBeFilePath(editor.document.uri.fsPath);
|
||||
if (typeof filePrefixOnFolder !== "undefined") {
|
||||
filePrefix = filePrefixOnFolder;
|
||||
}
|
||||
|
||||
let filePrefix = Settings.get<string>(SETTING_TEMPLATES_PREFIX);
|
||||
const contentType = ArticleHelper.getContentType(article.data);
|
||||
filePrefix = ArticleHelper.getFilePrefix(editor.document.uri.fsPath, contentType);
|
||||
|
||||
const titleField = "title";
|
||||
const articleTitle: string = article.data[titleField];
|
||||
const slugInfo = Article.generateSlug(articleTitle);
|
||||
@@ -259,7 +255,7 @@ export class Article {
|
||||
|
||||
let newFileName = `${slugName}${ext}`;
|
||||
if (filePrefix && typeof filePrefix === "string") {
|
||||
newFileName = `${format(new Date(), DateHelper.formatUpdate(filePrefix) as string)}-${newFileName}`;
|
||||
newFileName = `${filePrefix}-${newFileName}`;
|
||||
}
|
||||
|
||||
const newPath = editor.document.uri.fsPath.replace(fileName, newFileName);
|
||||
|
||||
@@ -13,11 +13,22 @@ export class Cache {
|
||||
);
|
||||
}
|
||||
|
||||
public static async get<T>(key: string, type: "workspace" | "global"): Promise<T | undefined> {
|
||||
const ext = Extension.getInstance();
|
||||
const cache = await ext.getState<T>(key, type);
|
||||
return cache || undefined;
|
||||
}
|
||||
|
||||
public static async set(key: string, data: any, type: "workspace" | "global") {
|
||||
await Extension.getInstance().setState(key, data, "workspace");
|
||||
}
|
||||
|
||||
private static async clear() {
|
||||
const ext = Extension.getInstance();
|
||||
|
||||
await ext.setState(ExtensionState.Dashboard.Pages.Cache, undefined, "workspace");
|
||||
await ext.setState(ExtensionState.Dashboard.Pages.Index, undefined, "workspace");
|
||||
await ext.setState(ExtensionState.Settings.Extends, undefined, "workspace");
|
||||
|
||||
Notifications.info("Cache cleared");
|
||||
}
|
||||
|
||||
@@ -199,7 +199,8 @@ export class Dashboard {
|
||||
|
||||
const csp = [
|
||||
`default-src 'none';`,
|
||||
`img-src ${`vscode-file://vscode-app`} ${webView.cspSource} https://api.visitorbadge.io 'self' 'unsafe-inline'`,
|
||||
`img-src ${`vscode-file://vscode-app`} ${webView.cspSource} https://api.visitorbadge.io 'self' 'unsafe-inline' https://*`,
|
||||
`media-src ${`vscode-file://vscode-app`} ${webView.cspSource} 'self' 'unsafe-inline' https://*`,
|
||||
`script-src ${isProd ? `'nonce-${nonce}'` : `http://${localServerUrl} http://0.0.0.0:${localPort}`} 'unsafe-eval'`,
|
||||
`style-src ${webView.cspSource} 'self' 'unsafe-inline'`,
|
||||
`font-src ${webView.cspSource}`,
|
||||
|
||||
@@ -253,14 +253,19 @@ export class Folders {
|
||||
try {
|
||||
let projectStart = parseWinPath(folder.path).replace(wsFolder, "");
|
||||
|
||||
if (projectStart) {
|
||||
if (typeof projectStart === 'string') {
|
||||
projectStart = projectStart.replace(/\\/g, '/');
|
||||
projectStart = projectStart.startsWith('/') ? projectStart.substring(1) : projectStart;
|
||||
|
||||
let files: Uri[] = [];
|
||||
|
||||
for (const fileType of (supportedFiles || DEFAULT_FILE_TYPES)) {
|
||||
const filePath = join(projectStart, folder.excludeSubdir ? '/' : '**', `*${fileType.startsWith('.') ? '' : '.'}${fileType}`);
|
||||
let filePath = join(projectStart, folder.excludeSubdir ? '/' : '**', `*${fileType.startsWith('.') ? '' : '.'}${fileType}`);
|
||||
|
||||
if (projectStart === '' && folder.excludeSubdir) {
|
||||
filePath = `*${fileType.startsWith('.') ? '' : '.'}${fileType}`;
|
||||
}
|
||||
|
||||
const foundFiles = await workspace.findFiles(filePath, '**/node_modules/**');
|
||||
files = [...files, ...foundFiles];
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ export const ExtensionState = {
|
||||
}
|
||||
},
|
||||
|
||||
Settings: {
|
||||
Extends: `frontMatter:Settings:Extends`,
|
||||
},
|
||||
|
||||
Updates: {
|
||||
v7_0_0: {
|
||||
dateFields: `frontMatter:Updates:v7.0.0:dateFields`
|
||||
|
||||
@@ -2,6 +2,8 @@ export const EXTENSION_NAME = "Front Matter";
|
||||
|
||||
export const CONFIG_KEY = "frontMatter";
|
||||
|
||||
export const SETTING_EXTENDS = "extends";
|
||||
|
||||
export const SETTING_GLOBAL_NOTIFICATIONS = "global.notifications";
|
||||
export const SETTING_GLOBAL_NOTIFICATIONS_DISABLED = "global.disabledNotifications";
|
||||
export const SETTING_GLOBAL_MODES = "global.modes";
|
||||
|
||||
@@ -321,10 +321,14 @@ export const Item: React.FunctionComponent<IItemProps> = ({media}: React.PropsWi
|
||||
}, [media, isImageFile, isVideoFile, isAudioFile]);
|
||||
|
||||
const renderMedia = useMemo(() => {
|
||||
if (isVideoFile || isAudioFile) {
|
||||
if (isAudioFile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isVideoFile) {
|
||||
return <video src={media.vsPath} className="mx-auto object-cover" controls muted />;
|
||||
}
|
||||
|
||||
if (isImageFile) {
|
||||
return <img src={media.vsPath} alt={basename(media.fsPath)} className="mx-auto object-cover" />;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
|
||||
{
|
||||
id: `welcome-init`,
|
||||
name: 'Initialize project',
|
||||
description: <>Initialize the project with a template folder and sample markdown file. The template folder can be used to define your own templates. <b>Start by clicking on this action</b>.</>,
|
||||
description: <>Initialize the project will create the required files and folders for using the Front Matter CMS. <b>Start by clicking on this action</b>.</>,
|
||||
status: settings.initialized ? Status.Completed : Status.NotStarted,
|
||||
onClick: settings.initialized ? undefined : () => { Messenger.send(DashboardMessage.initializeProject); }
|
||||
},
|
||||
|
||||
@@ -173,7 +173,7 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
|
||||
const csp = [
|
||||
`default-src 'none';`,
|
||||
`img-src ${`vscode-file://vscode-app`} ${webView.cspSource} https://api.visitorbadge.io 'self' 'unsafe-inline'`,
|
||||
`img-src ${`vscode-file://vscode-app`} ${webView.cspSource} https://api.visitorbadge.io 'self' 'unsafe-inline' https://*`,
|
||||
`script-src 'unsafe-eval' ${isProd ? `'nonce-${nonce}'` : `http://${localServerUrl} http://0.0.0.0:${localPort}`}`,
|
||||
`style-src ${webView.cspSource} 'self' 'unsafe-inline'`,
|
||||
`font-src ${webView.cspSource}`,
|
||||
|
||||
@@ -331,17 +331,10 @@ export class ArticleHelper {
|
||||
public static async createContent(contentType: ContentType | undefined, folderPath: string, titleValue: string, fileExtension?: string): Promise<string | undefined> {
|
||||
FrontMatterParser.currentContent = null;
|
||||
|
||||
let prefix = Settings.get<string>(SETTING_TEMPLATES_PREFIX);
|
||||
const fileType = Settings.get<string>(SETTING_CONTENT_DEFAULT_FILETYPE);
|
||||
|
||||
const filePrefixOnFolder = Folders.getFilePrefixByFolderPath(folderPath);
|
||||
if (typeof filePrefixOnFolder !== "undefined") {
|
||||
prefix = filePrefixOnFolder;
|
||||
}
|
||||
|
||||
if (prefix && typeof prefix === "string") {
|
||||
prefix = `${format(new Date(), DateHelper.formatUpdate(prefix) as string)}`;
|
||||
}
|
||||
let prefix = Settings.get<string>(SETTING_TEMPLATES_PREFIX);
|
||||
prefix = ArticleHelper.getFilePrefix(folderPath, contentType);
|
||||
|
||||
// Name of the file or folder to create
|
||||
let sanitizedName = ArticleHelper.sanitize(titleValue);
|
||||
@@ -379,6 +372,36 @@ export class ArticleHelper {
|
||||
return newFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the file prefix
|
||||
* @param filePath
|
||||
* @param contentType
|
||||
* @returns
|
||||
*/
|
||||
public static getFilePrefix(filePath?: string, contentType?: ContentType): string | undefined {
|
||||
let prefix = undefined;
|
||||
|
||||
// Retrieve the file prefix from the folder
|
||||
if (filePath) {
|
||||
const filePrefixOnFolder = Folders.getFilePrefixByFolderPath(filePath);
|
||||
if (typeof filePrefixOnFolder !== "undefined") {
|
||||
prefix = filePrefixOnFolder;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the file prefix from the content type
|
||||
if (contentType && typeof contentType.filePrefix !== "undefined") {
|
||||
prefix = contentType.filePrefix;
|
||||
}
|
||||
|
||||
// Process the prefix date formatting
|
||||
if (prefix && typeof prefix === "string") {
|
||||
prefix = `${format(new Date(), DateHelper.formatUpdate(prefix) as string)}`;
|
||||
}
|
||||
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update placeholder values in the front matter content
|
||||
* @param data
|
||||
@@ -437,7 +460,9 @@ export class ArticleHelper {
|
||||
// Do nothing
|
||||
}
|
||||
} else {
|
||||
output = output.split("\n");
|
||||
if (output.includes("\n")) {
|
||||
output = output.split("\n");
|
||||
}
|
||||
}
|
||||
|
||||
placeHolderValue = output;
|
||||
|
||||
@@ -121,7 +121,7 @@ export class ContentType {
|
||||
|
||||
const override = await window.showQuickPick(["Yes", "No"], {
|
||||
title: "Override default content type",
|
||||
placeHolder: "Do you want to override the default content type?",
|
||||
placeHolder: "Do you want to overwrite the default content type configuration with the fields used in the current field?",
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
const overrideBool = override === "Yes";
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Settings } from './SettingsHelper';
|
||||
import { CommandType } from './../models/PanelSettings';
|
||||
import { CommandType, EnvironmentType } from './../models/PanelSettings';
|
||||
import { CustomScript as ICustomScript, ScriptType } from '../models/PanelSettings';
|
||||
import { window, env as vscodeEnv, ProgressLocation } from 'vscode';
|
||||
import { ArticleHelper, Logger, Telemetry } from '.';
|
||||
import { Folders } from '../commands/Folders';
|
||||
import { exec } from 'child_process';
|
||||
import { Folders, WORKSPACE_PLACEHOLDER } from '../commands/Folders';
|
||||
import { exec, execSync } from 'child_process';
|
||||
import * as os from 'os';
|
||||
import { join } from 'path';
|
||||
import { Notifications } from './Notifications';
|
||||
@@ -186,7 +186,8 @@ export class CustomScript {
|
||||
try {
|
||||
let articleData = "";
|
||||
if (os.type() === "Windows_NT") {
|
||||
articleData = `"${JSON.stringify(article?.data).replace(/"/g, `""`)}"`;
|
||||
const jsonData = JSON.stringify(article?.data)
|
||||
articleData = `'${jsonData.replace(/"/g, `\"`)}'`;
|
||||
} else {
|
||||
articleData = JSON.stringify(article?.data).replace(/'/g, "%27");
|
||||
articleData = `'${articleData}'`;
|
||||
@@ -269,14 +270,41 @@ export class CustomScript {
|
||||
*/
|
||||
public static async executeScript(script: ICustomScript, wsPath: string, args: string): Promise<string> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
|
||||
const osType = os.type();
|
||||
|
||||
// Check the command to use
|
||||
let command = script.nodeBin || "node";
|
||||
if (script.command && script.command !== CommandType.Node) {
|
||||
command = script.command;
|
||||
}
|
||||
|
||||
const scriptPath = join(wsPath, script.script);
|
||||
let scriptPath = join(wsPath, script.script);
|
||||
if (script.script.includes(WORKSPACE_PLACEHOLDER)) {
|
||||
scriptPath = Folders.getAbsFilePath(script.script);
|
||||
}
|
||||
|
||||
// Check if there is an environments overwrite required
|
||||
if (script.environments) {
|
||||
let crntType: EnvironmentType | null = null;
|
||||
if (osType === "Windows_NT") {
|
||||
crntType = "windows"
|
||||
} else if (osType === "Darwin") {
|
||||
crntType = "macos"
|
||||
} else {
|
||||
crntType = "linux"
|
||||
}
|
||||
|
||||
const environment = script.environments.find(e => e.type === crntType);
|
||||
if (environment && environment.script && environment.command) {
|
||||
if (await CustomScript.validateCommand(environment.command)) {
|
||||
command = environment.command;
|
||||
scriptPath = join(wsPath, environment.script);
|
||||
if (environment.script.includes(WORKSPACE_PLACEHOLDER)) {
|
||||
scriptPath = Folders.getAbsFilePath(environment.script);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!await existsAsync(scriptPath)) {
|
||||
reject(new Error(`Script not found: ${scriptPath}`));
|
||||
@@ -301,4 +329,20 @@ export class CustomScript {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate if the command is exists
|
||||
* @param command
|
||||
* @returns
|
||||
*/
|
||||
private static async validateCommand(command: string) {
|
||||
try {
|
||||
execSync(command);
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
Logger.error(`Invalid command: ${command}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,14 +27,14 @@ export class ImageHelper {
|
||||
if (Array.isArray(value)) {
|
||||
previewUri = value.map(v => ({
|
||||
original: v,
|
||||
absPath: ImageHelper.relToAbs(filePath, v)
|
||||
absPath: v.startsWith("http") ? v : ImageHelper.relToAbs(filePath, v)
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
if (typeof value === "string") {
|
||||
return {
|
||||
original: value,
|
||||
absPath: ImageHelper.relToAbs(filePath, value)
|
||||
absPath: value.startsWith("http") ? value : ImageHelper.relToAbs(filePath, value)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -122,12 +122,12 @@ export class ImageHelper {
|
||||
if (field.multiple && imageData instanceof Array) {
|
||||
const preview = imageData.map(preview => preview && preview.absPath ? ({
|
||||
...preview,
|
||||
webviewUrl: panel.getWebview()?.asWebviewUri(preview.absPath).toString()
|
||||
webviewUrl: typeof preview.absPath === "string" ? preview.absPath : panel.getWebview()?.asWebviewUri(preview.absPath).toString()
|
||||
}) : null);
|
||||
|
||||
parentObj[field.name] = preview || [];
|
||||
} else if (!field.multiple && !Array.isArray(imageData) && imageData.absPath) {
|
||||
const preview = panel.getWebview()?.asWebviewUri(imageData.absPath);
|
||||
const preview = typeof imageData.absPath === "string" ? imageData.absPath : panel.getWebview()?.asWebviewUri(imageData.absPath);
|
||||
parentObj[field.name] = {
|
||||
...imageData,
|
||||
webviewUrl: preview ? preview.toString() : null
|
||||
|
||||
+208
-40
@@ -3,8 +3,8 @@ import { Telemetry } from './Telemetry';
|
||||
import { Notifications } from './Notifications';
|
||||
import { commands, Uri, workspace, window } from 'vscode';
|
||||
import * as vscode from 'vscode';
|
||||
import { ContentFolder, ContentType, CustomPlaceholder, CustomTaxonomy, DataFile, DataFolder, DataType, TaxonomyType } from '../models';
|
||||
import { SETTING_TAXONOMY_TAGS, SETTING_TAXONOMY_CATEGORIES, CONFIG_KEY, CONTEXT, ExtensionState, SETTING_TAXONOMY_CUSTOM, TelemetryEvent, COMMAND_NAME, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_CONTENT_PAGE_FOLDERS, SETTING_CONTENT_SNIPPETS, SETTING_CONTENT_PLACEHOLDERS, SETTING_CUSTOM_SCRIPTS, SETTING_DATA_FILES, SETTING_DATA_TYPES, SETTING_DATA_FOLDERS } from '../constants';
|
||||
import { ContentType, CustomTaxonomy, TaxonomyType } from '../models';
|
||||
import { SETTING_TAXONOMY_TAGS, SETTING_TAXONOMY_CATEGORIES, CONFIG_KEY, CONTEXT, ExtensionState, SETTING_TAXONOMY_CUSTOM, TelemetryEvent, COMMAND_NAME, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_CONTENT_PAGE_FOLDERS, SETTING_CONTENT_SNIPPETS, SETTING_CONTENT_PLACEHOLDERS, SETTING_CUSTOM_SCRIPTS, SETTING_DATA_FILES, SETTING_DATA_TYPES, SETTING_DATA_FOLDERS, SETTING_EXTENDS, SETTING_CONTENT_SORTING, SETTING_GLOBAL_MODES, SETTING_TAXONOMY_FIELD_GROUPS, SETTING_CONTENT_DRAFT_FIELD, SETTING_CONTENT_SUPPORTED_FILETYPES, SETTING_GLOBAL_NOTIFICATIONS, SETTING_GLOBAL_NOTIFICATIONS_DISABLED, SETTING_MEDIA_SUPPORTED_MIMETYPES, SETTING_COMMA_SEPARATED_FIELDS, SETTING_REMOVE_QUOTES } from '../constants';
|
||||
import { Folders } from '../commands/Folders';
|
||||
import { join, basename, dirname, parse } from 'path';
|
||||
import { existsSync } from 'fs';
|
||||
@@ -12,7 +12,8 @@ import { Extension } from './Extension';
|
||||
import { debounceCallback } from './DebounceCallback';
|
||||
import { Logger } from './Logger';
|
||||
import * as jsoncParser from 'jsonc-parser';
|
||||
import { existsAsync, readFileAsync, writeFileAsync } from '../utils';
|
||||
import { existsAsync, fetchWithTimeout, readFileAsync, writeFileAsync } from '../utils';
|
||||
import { Cache } from '../commands';
|
||||
|
||||
export class Settings {
|
||||
public static globalFile = "frontmatter.json";
|
||||
@@ -432,6 +433,9 @@ export class Settings {
|
||||
Settings.globalConfig = undefined;
|
||||
}
|
||||
|
||||
// Check if the config got external configs
|
||||
await Settings.processExternalConfig();
|
||||
|
||||
// Read the files from the config folder
|
||||
let configFiles = await workspace.findFiles(`**/${Settings.globalConfigFolder}/**/*.json`);
|
||||
if (configFiles.length === 0) {
|
||||
@@ -440,7 +444,6 @@ export class Settings {
|
||||
|
||||
// Sort the files by fsPath
|
||||
configFiles = configFiles.sort((a, b) => a.fsPath.localeCompare(b.fsPath));
|
||||
|
||||
for await (const configFile of configFiles) {
|
||||
await Settings.processConfigFile(configFile);
|
||||
}
|
||||
@@ -453,6 +456,25 @@ export class Settings {
|
||||
Settings.readConfigPromise = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the external configs
|
||||
*/
|
||||
private static async processExternalConfig() {
|
||||
const extendsConfigName = `${CONFIG_KEY}.${SETTING_EXTENDS}`;
|
||||
if (!Settings.globalConfig || !Settings.globalConfig[extendsConfigName]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const originalConfig = Object.assign({}, Settings.globalConfig);
|
||||
const extendsConfig: string[] = Settings.globalConfig[extendsConfigName];
|
||||
for (const externalConfig of extendsConfig) {
|
||||
if (externalConfig.endsWith(`.json`)) {
|
||||
const config = await Settings.getExternalConfig(externalConfig);
|
||||
await Settings.extendConfig(config, originalConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the config file
|
||||
* @param configFile
|
||||
@@ -482,45 +504,137 @@ export class Settings {
|
||||
Settings.globalConfig = {};
|
||||
}
|
||||
|
||||
// Array settings
|
||||
if (Settings.isEqualOrStartsWith(relSettingName, SETTING_CUSTOM_SCRIPTS)) {
|
||||
const crntValue = Settings.globalConfig[`${CONFIG_KEY}.${SETTING_CUSTOM_SCRIPTS}`] || [];
|
||||
Settings.globalConfig[`${CONFIG_KEY}.${SETTING_CUSTOM_SCRIPTS}`] = [...crntValue, configJson];
|
||||
}
|
||||
// Content types
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_TAXONOMY_CONTENT_TYPES)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_TAXONOMY_CONTENT_TYPES, "name", configJson);
|
||||
}
|
||||
// Data files
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_DATA_FILES)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_DATA_FILES, "id", configJson);
|
||||
}
|
||||
// Data folders
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_DATA_FOLDERS)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_DATA_FOLDERS, "id", configJson);
|
||||
}
|
||||
// Data types
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_DATA_TYPES)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_DATA_TYPES, "id", configJson);
|
||||
}
|
||||
// Page folders
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_CONTENT_PAGE_FOLDERS)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_CONTENT_PAGE_FOLDERS, "path", configJson);
|
||||
}
|
||||
// Placeholders
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_CONTENT_PLACEHOLDERS)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_CONTENT_PLACEHOLDERS, "id", configJson);
|
||||
}
|
||||
// Object settings
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_CONTENT_SNIPPETS)) {
|
||||
Settings.updateGlobalConfigObjectByNameSetting(SETTING_CONTENT_SNIPPETS, configFilePath, configJson, filePath);
|
||||
}
|
||||
Settings.updateGlobalConfigSetting(relSettingName, configJson, configFilePath, filePath);
|
||||
} catch (e) {
|
||||
Logger.error(`Error reading config file: ${configFile.fsPath}`);
|
||||
Logger.error((e as Error).message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the config with external config data
|
||||
* @param config
|
||||
* @param originalConfig The original config data is used to make sure we don't override settings coming from the fontmatter.json file.
|
||||
* @returns
|
||||
*/
|
||||
private static async extendConfig(config: any, originalConfig: any) {
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to loop through the config to make sure the objects and arrays are merged
|
||||
for (const key in config) {
|
||||
if (config.hasOwnProperty(key)) {
|
||||
const value = config[key];
|
||||
const settingName = key.replace(`${CONFIG_KEY}.`, '');
|
||||
|
||||
if (typeof value === 'string' ||
|
||||
typeof value === 'number' ||
|
||||
typeof value === 'boolean') {
|
||||
if (typeof originalConfig[key] === 'undefined') {
|
||||
Settings.globalConfig[key] = value;
|
||||
}
|
||||
}
|
||||
// Objects and arrays to override
|
||||
else if (settingName === SETTING_CONTENT_DRAFT_FIELD ||
|
||||
settingName === SETTING_CONTENT_SUPPORTED_FILETYPES ||
|
||||
settingName === SETTING_GLOBAL_NOTIFICATIONS ||
|
||||
settingName === SETTING_GLOBAL_NOTIFICATIONS_DISABLED ||
|
||||
settingName === SETTING_MEDIA_SUPPORTED_MIMETYPES ||
|
||||
settingName === SETTING_COMMA_SEPARATED_FIELDS) {
|
||||
if (typeof originalConfig[key] === 'undefined') {
|
||||
Settings.globalConfig[key] = value;
|
||||
}
|
||||
}
|
||||
else if (typeof value === 'object' && value !== null) {
|
||||
// Check if array
|
||||
if (Array.isArray(value)) {
|
||||
if (settingName === SETTING_TAXONOMY_CATEGORIES ||
|
||||
settingName === SETTING_TAXONOMY_TAGS ||
|
||||
settingName === SETTING_REMOVE_QUOTES) {
|
||||
// Merge the arrays
|
||||
Settings.globalConfig[key] = [...(Settings.globalConfig[key] || []), ...(originalConfig[key] || []), ...value];
|
||||
// Filter out the doubles
|
||||
Settings.globalConfig[key] = Settings.globalConfig[key].filter((item: any, index: number) => {
|
||||
return Settings.globalConfig[key].indexOf(item) === index;
|
||||
}, Settings.globalConfig[key]);
|
||||
} else {
|
||||
for (const item of value) {
|
||||
Settings.updateGlobalConfigSetting(settingName, item);
|
||||
}
|
||||
}
|
||||
} else if (settingName === SETTING_CONTENT_SNIPPETS) {
|
||||
for (const itemKey in value) {
|
||||
const crntValue = Settings.globalConfig[key] || {};
|
||||
|
||||
if (!crntValue[itemKey]) {
|
||||
Settings.globalConfig[key] = { ...crntValue, ...{ [itemKey]: value[itemKey] } };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the global config array/object settings
|
||||
* @param relSettingName
|
||||
* @param configJson
|
||||
*/
|
||||
private static updateGlobalConfigSetting<T>(relSettingName: string, configJson: any, configFilePath?: string, filePath?: string): void {
|
||||
// Custom scripts
|
||||
if (Settings.isEqualOrStartsWith(relSettingName, SETTING_CUSTOM_SCRIPTS)) {
|
||||
// const crntValue = Settings.globalConfig[`${CONFIG_KEY}.${SETTING_CUSTOM_SCRIPTS}`] || [];
|
||||
// Settings.globalConfig[`${CONFIG_KEY}.${SETTING_CUSTOM_SCRIPTS}`] = [...crntValue, configJson];
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_CUSTOM_SCRIPTS, "id", configJson, "script");
|
||||
}
|
||||
// Content types
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_TAXONOMY_CONTENT_TYPES)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_TAXONOMY_CONTENT_TYPES, "name", configJson);
|
||||
}
|
||||
// Data files
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_DATA_FILES)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_DATA_FILES, "id", configJson);
|
||||
}
|
||||
// Data folders
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_DATA_FOLDERS)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_DATA_FOLDERS, "id", configJson);
|
||||
}
|
||||
// Data types
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_DATA_TYPES)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_DATA_TYPES, "id", configJson);
|
||||
}
|
||||
// Page folders
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_CONTENT_PAGE_FOLDERS)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_CONTENT_PAGE_FOLDERS, "path", configJson);
|
||||
}
|
||||
// Placeholders
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_CONTENT_PLACEHOLDERS)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_CONTENT_PLACEHOLDERS, "id", configJson);
|
||||
}
|
||||
// Sorting
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_CONTENT_SORTING)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_CONTENT_SORTING, "id", configJson);
|
||||
}
|
||||
// Modes
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_GLOBAL_MODES)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_GLOBAL_MODES, "id", configJson);
|
||||
}
|
||||
// Field groups
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_TAXONOMY_FIELD_GROUPS)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_TAXONOMY_FIELD_GROUPS, "id", configJson);
|
||||
}
|
||||
// Custom taxonomy
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_TAXONOMY_CUSTOM)) {
|
||||
Settings.updateGlobalConfigArraySetting(SETTING_TAXONOMY_CUSTOM, "id", configJson);
|
||||
}
|
||||
// Snippets
|
||||
else if (Settings.isEqualOrStartsWith(relSettingName, SETTING_CONTENT_SNIPPETS) && configFilePath && filePath) {
|
||||
Settings.updateGlobalConfigObjectByNameSetting(SETTING_CONTENT_SNIPPETS, configFilePath, configJson, filePath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the setting name is equal or starts with the reference setting name
|
||||
* @param value
|
||||
@@ -540,11 +654,18 @@ export class Settings {
|
||||
* @param fieldName
|
||||
* @param configJson
|
||||
*/
|
||||
private static updateGlobalConfigArraySetting<T>(settingName: string, fieldName: string, configJson: any): void {
|
||||
private static updateGlobalConfigArraySetting<T>(settingName: string, fieldName: string, configJson: any, fallbackFieldName?: string): void {
|
||||
const crntValue: T[] = Settings.globalConfig[`${CONFIG_KEY}.${settingName}`] || [];
|
||||
|
||||
// Check if folder is already added
|
||||
const itemIdx = crntValue.findIndex((item: any) => item[fieldName] === configJson[fieldName]);
|
||||
const itemIdx = crntValue.findIndex((item: any) => {
|
||||
if (typeof item[fieldName] !== "undefined") {
|
||||
return item[fieldName] === configJson[fieldName];
|
||||
} else if (fallbackFieldName && typeof item[fallbackFieldName] !== "undefined") {
|
||||
return item[fallbackFieldName] === configJson[fallbackFieldName];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (itemIdx === -1) {
|
||||
crntValue.push(configJson);
|
||||
}
|
||||
@@ -606,4 +727,51 @@ export class Settings {
|
||||
l();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the external configuration
|
||||
* @param configPath
|
||||
* @returns
|
||||
*/
|
||||
private static async getExternalConfig(configPath: string): Promise<any> {
|
||||
let config: any = undefined;
|
||||
|
||||
if (configPath.startsWith('https://')) {
|
||||
try {
|
||||
let cachedResponse = await Cache.get<{[config: string]: { expires: number, data: any }}>(ExtensionState.Settings.Extends, "workspace");
|
||||
|
||||
if (cachedResponse && cachedResponse[configPath] && cachedResponse[configPath].expires > new Date().getTime()) {
|
||||
config = cachedResponse[configPath].data;
|
||||
} else {
|
||||
const response = await fetchWithTimeout(configPath, { method: 'GET' });
|
||||
if (response.ok) {
|
||||
config = await response.json();
|
||||
|
||||
if (!cachedResponse) {
|
||||
cachedResponse = {};
|
||||
}
|
||||
|
||||
cachedResponse[configPath] = {
|
||||
expires: (new Date(new Date().getTime() + (1000 * 60 * 10))).getTime(),
|
||||
data: config
|
||||
};
|
||||
|
||||
await Cache.set(ExtensionState.Settings.Extends, cachedResponse, "workspace");
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
Logger.error(`Error fetching external config "${configPath}".`);
|
||||
}
|
||||
} else {
|
||||
const absConfigPath = join(Folders.getWorkspaceFolder()?.fsPath || '', configPath);
|
||||
if (await existsAsync(absConfigPath)) {
|
||||
const configTxt = await readFileAsync(absConfigPath, 'utf8');
|
||||
config = jsoncParser.parse(configTxt);
|
||||
} else {
|
||||
Logger.error(`External config "${configPath}" not found.`);
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,7 @@ export interface ContentType {
|
||||
pageBundle?: boolean;
|
||||
template?: string;
|
||||
postScript?: string;
|
||||
filePrefix?: string;
|
||||
}
|
||||
|
||||
export type FieldType = "string" | "number" | "datetime" | "boolean" | "image" | "choice" | "tags" | "categories" | "draft" | "taxonomy" | "fields" | "json" | "block" | "file" | "dataFile" | "list" | "slug" | "divider" | "heading";
|
||||
@@ -148,6 +149,15 @@ export interface CustomScript {
|
||||
type?: ScriptType;
|
||||
command?: CommandType | string;
|
||||
hidden?: boolean;
|
||||
environments?: EnvironmentScript[];
|
||||
}
|
||||
|
||||
export type EnvironmentType = "windows" | "macos" | "linux";
|
||||
|
||||
export interface EnvironmentScript {
|
||||
type: EnvironmentType;
|
||||
script: string;
|
||||
command: CommandType | string;
|
||||
}
|
||||
|
||||
export interface PreviewSettings {
|
||||
|
||||
+28
-23
@@ -238,31 +238,36 @@ export class PagesParser {
|
||||
|
||||
// Revalidate as the array could have been empty
|
||||
if (fieldValue) {
|
||||
let staticPath = join(wsFolder.fsPath, staticFolder || "", fieldValue);
|
||||
// Check if the value already starts with https - if that is the case, it is an external image
|
||||
if (fieldValue.startsWith("http")) {
|
||||
page.fmPreviewImage = fieldValue;
|
||||
} else {
|
||||
let staticPath = join(wsFolder.fsPath, staticFolder || "", fieldValue);
|
||||
|
||||
if (staticFolder === STATIC_FOLDER_PLACEHOLDER.hexo.placeholder) {
|
||||
const crntFilePath = parseWinPath(filePath)
|
||||
const pathWithoutExtension = crntFilePath.replace(extname(crntFilePath), '');
|
||||
staticPath = join(pathWithoutExtension, fieldValue);
|
||||
}
|
||||
|
||||
const contentFolderPath = join(dirname(filePath), fieldValue);
|
||||
|
||||
let previewUri = null;
|
||||
if (await existsAsync(staticPath)) {
|
||||
previewUri = Uri.file(staticPath);
|
||||
} else if (await existsAsync(contentFolderPath)) {
|
||||
previewUri = Uri.file(contentFolderPath);
|
||||
}
|
||||
|
||||
if (previewUri) {
|
||||
let previewPath = Dashboard.getWebview()?.asWebviewUri(previewUri);
|
||||
|
||||
if (!previewPath) {
|
||||
previewPath = PagesParser.getWebviewUri(previewUri);
|
||||
if (staticFolder === STATIC_FOLDER_PLACEHOLDER.hexo.placeholder) {
|
||||
const crntFilePath = parseWinPath(filePath)
|
||||
const pathWithoutExtension = crntFilePath.replace(extname(crntFilePath), '');
|
||||
staticPath = join(pathWithoutExtension, fieldValue);
|
||||
}
|
||||
|
||||
const contentFolderPath = join(dirname(filePath), fieldValue);
|
||||
|
||||
let previewUri = null;
|
||||
if (await existsAsync(staticPath)) {
|
||||
previewUri = Uri.file(staticPath);
|
||||
} else if (await existsAsync(contentFolderPath)) {
|
||||
previewUri = Uri.file(contentFolderPath);
|
||||
}
|
||||
|
||||
if (previewUri) {
|
||||
let previewPath = Dashboard.getWebview()?.asWebviewUri(previewUri);
|
||||
|
||||
if (!previewPath) {
|
||||
previewPath = PagesParser.getWebviewUri(previewUri);
|
||||
}
|
||||
|
||||
page["fmPreviewImage"] = previewPath?.toString() || "";
|
||||
}
|
||||
|
||||
page["fmPreviewImage"] = previewPath?.toString() || "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
export const fetchWithTimeout = async (url: string, options: any, timeout = 5000) => {
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const id = setTimeout(() => controller.abort(), timeout);
|
||||
const response = await fetch(url, { ...options, signal: controller.signal });
|
||||
clearTimeout(id);
|
||||
return response;
|
||||
} catch (error) {
|
||||
throw new Error(`Request timed out: ${url}`);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
export * from './copyFileAsync';
|
||||
export * from './existsAsync';
|
||||
export * from './fetchWithTimeout';
|
||||
export * from './fieldWhenClause';
|
||||
export * from './mkdirAsync';
|
||||
export * from './readFileAsync';
|
||||
|
||||
Reference in New Issue
Block a user