Refactor: refine writing strategy
Some checks are pending
Build / Build (push) Waiting to run
Build / Diff output (push) Blocked by required conditions
Build / Deploy to Cloudflare Pages (push) Blocked by required conditions
Build / Deploy to GitHub and GitLab (push) Blocked by required conditions

This commit is contained in:
SukkaW 2025-02-01 00:04:09 +08:00
parent 3926fb3484
commit 2035f5ea96
8 changed files with 41 additions and 35 deletions

View File

@ -8,7 +8,7 @@ import { fastStringArrayJoin } from 'foxts/fast-string-array-join';
import { readFileByLine } from '../fetch-text-by-line'; import { readFileByLine } from '../fetch-text-by-line';
import { asyncWriteToStream } from 'foxts/async-write-to-stream'; import { asyncWriteToStream } from 'foxts/async-write-to-stream';
import type { BaseWriteStrategy } from '../writing-strategy/base'; import type { BaseWriteStrategy } from '../writing-strategy/base';
import { merge } from 'fast-cidr-tools'; import { merge as mergeCidr } from 'fast-cidr-tools';
import { createRetrieKeywordFilter as createKeywordFilter } from 'foxts/retrie'; import { createRetrieKeywordFilter as createKeywordFilter } from 'foxts/retrie';
import path from 'node:path'; import path from 'node:path';
import { SurgeMitmSgmodule } from '../writing-strategy/surge'; import { SurgeMitmSgmodule } from '../writing-strategy/surge';
@ -369,10 +369,10 @@ export class FileOutput {
let ipcidr6NoResolve: string[] | null = null; let ipcidr6NoResolve: string[] | null = null;
if (this.ipcidr.size) { if (this.ipcidr.size) {
ipcidr = merge(Array.from(this.ipcidr), true); ipcidr = mergeCidr(Array.from(this.ipcidr), true);
} }
if (this.ipcidrNoResolve.size) { if (this.ipcidrNoResolve.size) {
ipcidrNoResolve = merge(Array.from(this.ipcidrNoResolve), true); ipcidrNoResolve = mergeCidr(Array.from(this.ipcidrNoResolve), true);
} }
if (this.ipcidr6.size) { if (this.ipcidr6.size) {
ipcidr6 = Array.from(this.ipcidr6); ipcidr6 = Array.from(this.ipcidr6);
@ -433,9 +433,12 @@ export class FileOutput {
this.title, this.title,
this.description, this.description,
this.date, this.date,
strategy.type path.join(
? path.join(strategy.type, basename) strategy.outputDir,
: basename strategy.type
? path.join(strategy.type, basename)
: basename
)
)); ));
} }
} }

View File

@ -7,12 +7,10 @@ import { SurgeDomainSet } from '../writing-strategy/surge';
import { FileOutput } from './base'; import { FileOutput } from './base';
export class DomainsetOutput extends FileOutput { export class DomainsetOutput extends FileOutput {
protected type = 'domainset' as const;
strategies: Array<false | BaseWriteStrategy> = [ strategies: Array<false | BaseWriteStrategy> = [
new SurgeDomainSet(), new SurgeDomainSet(),
new ClashDomainSet(), new ClashDomainSet(),
new SingboxSource(this.type) new SingboxSource('domainset')
]; ];
} }

View File

@ -6,16 +6,15 @@ import { SurgeRuleSet } from '../writing-strategy/surge';
import { FileOutput } from './base'; import { FileOutput } from './base';
export class IPListOutput extends FileOutput { export class IPListOutput extends FileOutput {
protected type = 'ip' as const;
strategies: Array<false | BaseWriteStrategy>; strategies: Array<false | BaseWriteStrategy>;
constructor(span: Span, id: string, private readonly clashUseRule = true) { constructor(span: Span, id: string, private readonly clashUseRule = true) {
super(span, id); super(span, id);
this.strategies = [ this.strategies = [
new SurgeRuleSet(this.type), new SurgeRuleSet('ip'),
this.clashUseRule ? new ClashClassicRuleSet(this.type) : new ClashIPSet(), this.clashUseRule ? new ClashClassicRuleSet('ip') : new ClashIPSet(),
new SingboxSource(this.type) new SingboxSource('ip')
]; ];
} }
} }

View File

@ -5,13 +5,13 @@ import { SurgeRuleSet } from '../writing-strategy/surge';
import { FileOutput } from './base'; import { FileOutput } from './base';
export class RulesetOutput extends FileOutput { export class RulesetOutput extends FileOutput {
constructor(span: Span, id: string, protected type: 'non_ip' | 'ip' | (string & {})) { constructor(span: Span, id: string, type: 'non_ip' | 'ip') {
super(span, id); super(span, id);
this.strategies = [ this.strategies = [
new SurgeRuleSet(this.type), new SurgeRuleSet(type),
new ClashClassicRuleSet(this.type), new ClashClassicRuleSet(type),
new SingboxSource(this.type) new SingboxSource(type)
]; ];
} }
} }
@ -20,13 +20,13 @@ export class SurgeOnlyRulesetOutput extends FileOutput {
constructor( constructor(
span: Span, span: Span,
id: string, id: string,
protected type: 'non_ip' | 'ip' | (string & {}), type: 'non_ip' | 'ip' | (string & {}),
overrideOutputDir?: string overrideOutputDir?: string
) { ) {
super(span, id); super(span, id);
this.strategies = [ this.strategies = [
new SurgeRuleSet(this.type, overrideOutputDir) new SurgeRuleSet(type, overrideOutputDir)
]; ];
} }
} }
@ -35,12 +35,12 @@ export class ClashOnlyRulesetOutput extends FileOutput {
constructor( constructor(
span: Span, span: Span,
id: string, id: string,
protected type: 'non_ip' | 'ip' | (string & {}) type: 'non_ip' | 'ip'
) { ) {
super(span, id); super(span, id);
this.strategies = [ this.strategies = [
new ClashClassicRuleSet(this.type) new ClashClassicRuleSet(type)
]; ];
} }
} }

View File

@ -1,15 +1,13 @@
import path from 'node:path';
import type { Span } from '../../trace'; import type { Span } from '../../trace';
import { compareAndWriteFile } from '../create-file'; import { compareAndWriteFile } from '../create-file';
export abstract class BaseWriteStrategy { export abstract class BaseWriteStrategy {
// abstract readonly type: 'domainset' | 'non_ip' | 'ip' | (string & {});
public overwriteFilename: string | null = null; public overwriteFilename: string | null = null;
public abstract readonly type: 'domainset' | 'non_ip' | 'ip' | (string & {}); public abstract readonly type: 'domainset' | 'non_ip' | 'ip' | (string & {});
abstract readonly fileExtension: 'conf' | 'txt' | 'json' | (string & {}); abstract readonly fileExtension: 'conf' | 'txt' | 'json' | (string & {});
constructor(protected outputDir: string) {} constructor(public readonly outputDir: string) {}
protected abstract result: string[] | null; protected abstract result: string[] | null;
@ -51,14 +49,14 @@ export abstract class BaseWriteStrategy {
return result; return result;
}; };
abstract withPadding(title: string, description: string[] | readonly string[], date: Date, content: string[]): string[]; protected abstract withPadding(title: string, description: string[] | readonly string[], date: Date, content: string[]): string[];
output( public output(
span: Span, span: Span,
title: string, title: string,
description: string[] | readonly string[], description: string[] | readonly string[],
date: Date, date: Date,
relativePath: string filePath: string
): void | Promise<void> { ): void | Promise<void> {
if (!this.result) { if (!this.result) {
return; return;
@ -71,11 +69,11 @@ export abstract class BaseWriteStrategy {
date, date,
this.result this.result
), ),
path.join(this.outputDir, relativePath) filePath
); );
}; };
get content() { public get content() {
return this.result; return this.result;
} }
} }

View File

@ -12,7 +12,7 @@ export class ClashDomainSet extends BaseWriteStrategy {
protected result: string[] = ['this_ruleset_is_made_by_sukkaw.ruleset.skk.moe']; protected result: string[] = ['this_ruleset_is_made_by_sukkaw.ruleset.skk.moe'];
constructor(protected outputDir = OUTPUT_CLASH_DIR) { constructor(public readonly outputDir = OUTPUT_CLASH_DIR) {
super(outputDir); super(outputDir);
} }
@ -49,7 +49,7 @@ export class ClashIPSet extends BaseWriteStrategy {
protected result: string[] = []; protected result: string[] = [];
constructor(protected outputDir = OUTPUT_CLASH_DIR) { constructor(public readonly outputDir = OUTPUT_CLASH_DIR) {
super(outputDir); super(outputDir);
} }
@ -84,7 +84,7 @@ export class ClashClassicRuleSet extends BaseWriteStrategy {
protected result: string[] = ['DOMAIN,this_ruleset_is_made_by_sukkaw.ruleset.skk.moe']; protected result: string[] = ['DOMAIN,this_ruleset_is_made_by_sukkaw.ruleset.skk.moe'];
constructor(public readonly type: string, protected outputDir = OUTPUT_CLASH_DIR) { constructor(public readonly type: 'ip' | 'non_ip' /* | (string & {}) */, public readonly outputDir = OUTPUT_CLASH_DIR) {
super(outputDir); super(outputDir);
} }

View File

@ -42,7 +42,11 @@ export class SingboxSource extends BaseWriteStrategy {
}); });
} }
constructor(public type: string, protected outputDir = OUTPUT_SINGBOX_DIR) { constructor(
/** Since sing-box only have one format that does not reflect type, we need to specify it */
public type: 'domainset' | 'non_ip' | 'ip' /* | (string & {}) */,
public readonly outputDir = OUTPUT_SINGBOX_DIR
) {
super(outputDir); super(outputDir);
} }

View File

@ -50,7 +50,11 @@ export class SurgeRuleSet extends BaseWriteStrategy {
protected result: string[] = ['DOMAIN,this_ruleset_is_made_by_sukkaw.ruleset.skk.moe']; protected result: string[] = ['DOMAIN,this_ruleset_is_made_by_sukkaw.ruleset.skk.moe'];
constructor(public readonly type: string, outputDir = OUTPUT_SURGE_DIR) { constructor(
/** Surge RULE-SET can be both ip or non_ip, so this needs to be specified */
public readonly type: 'ip' | 'non_ip' | (string & {}),
public readonly outputDir = OUTPUT_SURGE_DIR
) {
super(outputDir); super(outputDir);
} }
@ -130,7 +134,7 @@ export class SurgeRuleSet extends BaseWriteStrategy {
export class SurgeMitmSgmodule extends BaseWriteStrategy { export class SurgeMitmSgmodule extends BaseWriteStrategy {
// readonly type = 'domainset'; // readonly type = 'domainset';
readonly fileExtension = 'sgmodule'; readonly fileExtension = 'sgmodule';
type = ''; readonly type = '';
private rules = new Set<string>(); private rules = new Set<string>();