zenn-model 0.2.6-alpha.2 → 0.2.6-alpha.3

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.
Files changed (3) hide show
  1. package/lib/index.js +3 -3
  2. package/lib/utils.js +26 -52
  3. package/package.json +15 -15
package/lib/index.js CHANGED
@@ -16,13 +16,13 @@ var __copyProps = (to, from, except, desc) => {
16
16
  return to;
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var src_exports = {};
20
- __export(src_exports, {
19
+ var index_exports = {};
20
+ __export(index_exports, {
21
21
  validateArticle: () => validateArticle,
22
22
  validateBook: () => validateBook,
23
23
  validateBookChapter: () => validateBookChapter
24
24
  });
25
- module.exports = __toCommonJS(src_exports);
25
+ module.exports = __toCommonJS(index_exports);
26
26
  var import_utils = require("./utils");
27
27
  function getValidationErrors(item, validators) {
28
28
  return validators.reduce((errors, validator) => {
package/lib/utils.js CHANGED
@@ -65,13 +65,11 @@ module.exports = __toCommonJS(utils_exports);
65
65
  var import_emoji_regex = __toESM(require("emoji-regex"));
66
66
  var cheerio = __toESM(require("cheerio"));
67
67
  function validateSlug(slug) {
68
- if (!slug)
69
- return false;
68
+ if (!slug) return false;
70
69
  return /^[0-9a-z\-_]{12,50}$/.test(slug);
71
70
  }
72
71
  function validateChapterSlug(slug) {
73
- if (!slug)
74
- return false;
72
+ if (!slug) return false;
75
73
  return /^[0-9a-z\-_]{1,50}$/.test(slug) || /^[0-9]+.[0-9a-z\-_]{1,50}$/.test(slug);
76
74
  }
77
75
  function isAnyText(val) {
@@ -94,8 +92,7 @@ const validateTitleLength = {
94
92
  isCritical: true,
95
93
  getMessage: () => "\u30BF\u30A4\u30C8\u30EB\u306F70\u5B57\u4EE5\u5185\u306B\u3057\u3066\u304F\u3060\u3055\u3044",
96
94
  isValid: ({ title }) => {
97
- if (!isAnyText(title))
98
- return true;
95
+ if (!isAnyText(title)) return true;
99
96
  return title.length <= 70;
100
97
  }
101
98
  };
@@ -113,10 +110,8 @@ const validatePublishedAtParse = {
113
110
  isCritical: true,
114
111
  getMessage: () => "published_at\uFF08\u516C\u958B\u65E5\u6642\uFF09\u306F `YYYY-MM-DD` \u307E\u305F\u306F `YYYY-MM-DD hh:mm` \u306E\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044",
115
112
  isValid: ({ published_at: publishedAt }) => {
116
- if (publishedAt == void 0)
117
- return true;
118
- if (!publishedAt.match(PUBLISHED_AT_PATTERN))
119
- return false;
113
+ if (publishedAt == void 0) return true;
114
+ if (!publishedAt.match(PUBLISHED_AT_PATTERN)) return false;
120
115
  return !isNaN(Date.parse(publishedAt.replace(" ", "T")));
121
116
  }
122
117
  };
@@ -125,10 +120,8 @@ const validatePublishedAtSchedule = {
125
120
  isCritical: true,
126
121
  getMessage: () => "published_at\uFF08\u516C\u958B\u65E5\u6642\uFF09\u306B\u672A\u6765\u306E\u65E5\u6642\u3092\u6307\u5B9A\u3059\u308B\u5834\u5408\u306F\u3001published\uFF08\u516C\u958B\u8A2D\u5B9A\uFF09\u306B true \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u516C\u958B\u65E5\u6642\u3092\u904E\u304E\u308B\u3068Zenn\u306E\u30B5\u30FC\u30D3\u30B9\u4E0A\u3067\u81EA\u52D5\u7684\u306B\u516C\u958B\u3055\u308C\u307E\u3059\uFF09",
127
122
  isValid: ({ published, published_at: publishedAt }) => {
128
- if (published === true)
129
- return true;
130
- if (publishedAt == null)
131
- return true;
123
+ if (published === true) return true;
124
+ if (publishedAt == null) return true;
132
125
  if (isNaN(Date.parse(publishedAt))) {
133
126
  return true;
134
127
  } else {
@@ -143,8 +136,7 @@ const validateArticleType = {
143
136
  detailUrlText: "\u8A73\u7D30\u3092\u958B\u304F",
144
137
  getMessage: () => "type\uFF08\u8A18\u4E8B\u306E\u30BF\u30A4\u30D7\uFF09\u306B tech \u3082\u3057\u304F\u306F idea \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u6280\u8853\u8A18\u4E8B\u306E\u5834\u5408\u306F tech \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044",
145
138
  isValid: ({ type }) => {
146
- if (!type)
147
- return false;
139
+ if (!type) return false;
148
140
  return type === "tech" || type === "idea";
149
141
  }
150
142
  };
@@ -160,12 +152,10 @@ const validateEmojiFormat = {
160
152
  isCritical: true,
161
153
  getMessage: () => "\u7D75\u6587\u5B57\uFF08emoji\uFF09\u30921\u3064\u3060\u3051\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044",
162
154
  isValid: ({ emoji }) => {
163
- if (!isAnyText(emoji))
164
- return true;
155
+ if (!isAnyText(emoji)) return true;
165
156
  const emojiRegex = (0, import_emoji_regex.default)();
166
157
  const matches = emoji.match(emojiRegex);
167
- if (!matches || !matches[0] || matches[1])
168
- return false;
158
+ if (!matches || !matches[0] || matches[1]) return false;
169
159
  return true;
170
160
  }
171
161
  };
@@ -174,8 +164,7 @@ const validateMissingTopics = {
174
164
  isCritical: false,
175
165
  getMessage: () => 'topics\uFF08\u8A18\u4E8B\u306B\u95A2\u9023\u3059\u308B\u8A00\u8A9E\u3084\u6280\u8853\uFF09\u3092\u914D\u5217\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u4F8B\uFF09["react", "javascript"]',
176
166
  isValid: ({ topics }) => {
177
- if (!Array.isArray(topics))
178
- return false;
167
+ if (!Array.isArray(topics)) return false;
179
168
  return topics.length > 0;
180
169
  }
181
170
  };
@@ -184,8 +173,7 @@ const validateTooManyTopics = {
184
173
  isCritical: true,
185
174
  getMessage: () => "topics\u306F\u6700\u59275\u3064\u307E\u3067\u6307\u5B9A\u3067\u304D\u307E\u3059",
186
175
  isValid: ({ topics }) => {
187
- if (!Array.isArray(topics))
188
- return true;
176
+ if (!Array.isArray(topics)) return true;
189
177
  return topics.length <= 5;
190
178
  }
191
179
  };
@@ -194,8 +182,7 @@ const validateTopicType = {
194
182
  isCritical: true,
195
183
  getMessage: () => "topics\u306F\u5168\u3066\u6587\u5B57\u5217\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044",
196
184
  isValid: ({ topics }) => {
197
- if (!Array.isArray(topics))
198
- return true;
185
+ if (!Array.isArray(topics)) return true;
199
186
  return topics.every((t) => typeof t === "string" && t.length > 0);
200
187
  }
201
188
  };
@@ -204,10 +191,8 @@ const validateTopicLength = {
204
191
  isCritical: true,
205
192
  getMessage: () => "topics\u306F18\u5B57\u4EE5\u5185\u306B\u3057\u3066\u304F\u3060\u3055\u3044",
206
193
  isValid: ({ topics }) => {
207
- if (!Array.isArray(topics))
208
- return true;
209
- if (topics.some((t) => typeof t !== "string"))
210
- return true;
194
+ if (!Array.isArray(topics)) return true;
195
+ if (topics.some((t) => typeof t !== "string")) return true;
211
196
  return topics.every((t) => typeof t === "string" && t.length <= 18);
212
197
  }
213
198
  };
@@ -215,8 +200,7 @@ const validateInvalidTopicLetters = {
215
200
  type: "invalid-topic-letters",
216
201
  getMessage: () => "topics\u306B\u8A18\u53F7\u3084\u30B9\u30DA\u30FC\u30B9\u3092\u4F7F\u7528\u3059\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093\u3002\u4F8B\u3048\u3070C++\u306F\u300Ccpp\u300D\u3001C#\u306F\u300Ccsharp\u300D\u3068\u8A18\u8F09\u3057\u3066\u304F\u3060\u3055\u3044",
217
202
  isValid: ({ topics }) => {
218
- if (!Array.isArray(topics))
219
- return true;
203
+ if (!Array.isArray(topics)) return true;
220
204
  const anyInvalidFormat = topics.some(
221
205
  (t) => typeof t === "string" && t.match(/[ -/:-@[-`{-~]/g)
222
206
  );
@@ -233,8 +217,7 @@ const validatePublicationName = {
233
217
  isCritical: true,
234
218
  getMessage: () => "Publication\u306E\u540D\u524D\u304C\u4E0D\u6B63\u3067\u3059\u3002\u5C0F\u6587\u5B57\u306E\u534A\u89D2\u82F1\u6570\u5B57\uFF08a-z0-9\uFF09\u3001\u30A2\u30F3\u30C0\u30FC\u30B9\u30B3\u30A2\uFF08_\uFF09\u306E2\u301C15\u5B57\u306E\u7D44\u307F\u5408\u308F\u305B\u306B\u3057\u3066\u304F\u3060\u3055\u3044",
235
219
  isValid: ({ publication_name }) => {
236
- if (!publication_name)
237
- return true;
220
+ if (!publication_name) return true;
238
221
  return /^[0-9a-z_]{2,15}$/.test(publication_name);
239
222
  }
240
223
  };
@@ -255,10 +238,8 @@ const validateBookPriceRange = {
255
238
  isCritical: true,
256
239
  getMessage: () => "price\uFF08\u672C\u306E\u4FA1\u683C\uFF09\u3092\u6709\u6599\u306B\u3059\u308B\u5834\u5408\u3001200\u301C5000\u306E\u9593\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044",
257
240
  isValid: ({ price }) => {
258
- if (typeof price !== "number")
259
- return true;
260
- if (price === 0)
261
- return true;
241
+ if (typeof price !== "number") return true;
242
+ if (price === 0) return true;
262
243
  return price >= 200 && price <= 5e3;
263
244
  }
264
245
  };
@@ -267,8 +248,7 @@ const validateBookPriceFraction = {
267
248
  isCritical: true,
268
249
  getMessage: () => "price\uFF08\u672C\u306E\u4FA1\u683C\uFF09\u306F100\u5186\u5358\u4F4D\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044",
269
250
  isValid: ({ price }) => {
270
- if (typeof price !== "number")
271
- return true;
251
+ if (typeof price !== "number") return true;
272
252
  return price % 100 === 0;
273
253
  }
274
254
  };
@@ -282,14 +262,12 @@ const validateBookCoverSize = {
282
262
  isCritical: true,
283
263
  getMessage: (item) => `\u30AB\u30D0\u30FC\u753B\u50CF\u306E\u30B5\u30A4\u30BA\u306F1MB\u4EE5\u5185\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u73FE\u5728\u306E\u30B5\u30A4\u30BA: ${item.coverFilesize ? `${Math.trunc(item.coverFilesize / 1024)}KB` : "\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F"}`,
284
264
  isValid: ({ coverDataUrl, coverFilesize }) => {
285
- if (typeof coverDataUrl !== "string")
286
- return true;
265
+ if (typeof coverDataUrl !== "string") return true;
287
266
  return typeof coverFilesize === "number" && coverFilesize <= 1024 * 1024;
288
267
  }
289
268
  };
290
269
  function getAspectRatio(width, height) {
291
- if (!height || !width)
292
- return null;
270
+ if (!height || !width) return null;
293
271
  return Math.round(height / width * 10) / 10;
294
272
  }
295
273
  const validateBookCoverAspectRatio = {
@@ -302,8 +280,7 @@ const validateBookCoverAspectRatio = {
302
280
  return `\u30AB\u30D0\u30FC\u753B\u50CF\u306E\u300C\u5E45 : \u9AD8\u3055\u300D\u306E\u6BD4\u7387\u306F\u300C1 : 1.4\u300D\u306B\u3059\u308B\u3053\u3068\u3092\u304A\u3059\u3059\u3081\u3057\u307E\u3059\uFF08\u6700\u7D42\u7684\u306B\u5E45500px\u30FB\u9AD8\u3055700px\u306B\u30EA\u30B5\u30A4\u30BA\u3055\u308C\u307E\u3059\uFF09\u3002${currentAspectRatio ? `\u73FE\u5728\u306E\u6BD4\u7387\u306F\u300C1 : ${currentAspectRatio}\u300D\u3067\u3059` : ""}`;
303
281
  },
304
282
  isValid: ({ coverDataUrl, coverHeight, coverWidth }) => {
305
- if (typeof coverDataUrl !== "string")
306
- return true;
283
+ if (typeof coverDataUrl !== "string") return true;
307
284
  const currentAspectRatio = getAspectRatio(coverWidth, coverHeight);
308
285
  return typeof currentAspectRatio === "number" && currentAspectRatio === 1.4;
309
286
  }
@@ -314,8 +291,7 @@ const validateBookChapterSlugs = {
314
291
  getMessage: () => `config.yaml\u306E chapters \u306E\u6307\u5B9A\u306B\u8AA4\u308A\u304C\u3042\u308A\u307E\u3059`,
315
292
  detailUrl: "https://zenn.dev/zenn/articles/zenn-cli-guide#%F0%9F%93%84-config.yaml",
316
293
  isValid: ({ specifiedChapterSlugs }) => {
317
- if (specifiedChapterSlugs === void 0)
318
- return true;
294
+ if (specifiedChapterSlugs === void 0) return true;
319
295
  return Array.isArray(specifiedChapterSlugs) && specifiedChapterSlugs.every((slug) => typeof slug === "string");
320
296
  }
321
297
  };
@@ -325,8 +301,7 @@ const validateBookChaptersFormat = {
325
301
  getMessage: () => `chapters \u306B\u6307\u5B9A\u3059\u308B\u6587\u5B57\u5217\u306B\u306F\u62E1\u5F35\u5B50\uFF08.md\uFF09\u3092\u542B\u3081\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002\u30D5\u30A1\u30A4\u30EB\u540D\u304C example.md \u3067\u3042\u308C\u3070 example \u3068\u306E\u307F\u8A18\u8F09\u3057\u3066\u304F\u3060\u3055\u3044`,
326
302
  detailUrl: "https://zenn.dev/zenn/articles/zenn-cli-guide#%F0%9F%93%84-config.yaml",
327
303
  isValid: ({ specifiedChapterSlugs }) => {
328
- if (!Array.isArray(specifiedChapterSlugs))
329
- return true;
304
+ if (!Array.isArray(specifiedChapterSlugs)) return true;
330
305
  const anyInvalidFormat = specifiedChapterSlugs.some(
331
306
  (slug) => typeof slug === "string" && slug.match(/\.md$/)
332
307
  );
@@ -351,8 +326,7 @@ const validateBody = {
351
326
  getMessage: () => `\u8A18\u4E8B\u672C\u6587\u306B\u30A8\u30E9\u30FC\u304C\u3042\u308A\u307E\u3059\u3002\u672C\u6587\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002`,
352
327
  // data-body-error がある場合はエラー
353
328
  isValid: ({ bodyHtml }) => {
354
- if (!bodyHtml)
355
- return true;
329
+ if (!bodyHtml) return true;
356
330
  const $ = cheerio.load(bodyHtml);
357
331
  return !$("[data-body-error]").length;
358
332
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zenn-model",
3
- "version": "0.2.6-alpha.2",
3
+ "version": "0.2.6-alpha.3",
4
4
  "license": "MIT",
5
5
  "description": "Model utils for Zenn contents",
6
6
  "main": "lib/index.js",
@@ -18,29 +18,29 @@
18
18
  "build:src": "esbuild ./src/*.ts --format=cjs --outdir=lib",
19
19
  "build:types": "tsc --project ./tsconfig.build.json",
20
20
  "lint": "run-s lint:*",
21
- "lint:eslint": "eslint . --ext .ts,.tsx",
21
+ "lint:eslint": "eslint .",
22
22
  "lint:prettier": "prettier .",
23
23
  "lint-strict": "run-s lint-strict:*",
24
- "lint-strict:eslint": "eslint . --ext .ts,.tsx --max-warnings 0",
24
+ "lint-strict:eslint": "eslint . --max-warnings 0",
25
25
  "lint-strict:prettier": "prettier --check .",
26
26
  "fix": "run-s fix:*",
27
- "fix:eslint": "eslint . --ext .ts,.tsx --fix",
27
+ "fix:eslint": "eslint . --fix",
28
28
  "fix:prettier": "prettier -w .",
29
29
  "test": "vitest run"
30
30
  },
31
31
  "devDependencies": {
32
- "@typescript-eslint/eslint-plugin": "^5.52.0",
33
- "@typescript-eslint/parser": "^5.52.0",
34
- "esbuild": "^0.17.8",
35
- "eslint": "^8.34.0",
36
- "eslint-config-prettier": "^8.6.0",
37
- "rimraf": "^4.1.2",
38
- "typescript": "^4.9.5",
39
- "vitest": "^0.34.4"
32
+ "@eslint/js": "^9.38.0",
33
+ "esbuild": "^0.25.11",
34
+ "eslint": "^9.38.0",
35
+ "eslint-config-prettier": "^10.1.8",
36
+ "rimraf": "^6.0.1",
37
+ "typescript": "^5.9.3",
38
+ "typescript-eslint": "^8.46.2",
39
+ "vitest": "^3.2.4"
40
40
  },
41
41
  "dependencies": {
42
- "cheerio": "^1.0.0-rc.12",
43
- "emoji-regex": "^10.2.1"
42
+ "cheerio": "^1.1.2",
43
+ "emoji-regex": "^10.6.0"
44
44
  },
45
- "gitHead": "ed749f4454126290e65a539e47e438b3145d4254"
45
+ "gitHead": "9cca382bdb5638330513bdabac3e015022dbf73b"
46
46
  }